diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c96a7f..3c1e2b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: python-version: ${{ matrix.python-version }} - uses: astral-sh/setup-uv@v3 - name: Install deps - run: uv sync --extra dev + run: uv sync --extra dev --extra rust --extra aspose - name: Unit tests with coverage run: > uv run pytest diff --git a/.gitignore b/.gitignore index 1ca3a1b..9baa337 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,6 @@ output/ logs/ *.log .vercel + +# regenerable fixture-merge byproduct (scripts/build_tier4_fixtures.py) +fixtures/excel/tier4_manifest_fragment.json diff --git a/CLAUDE.md b/CLAUDE.md index f97702d..7e4a0a6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,6 +43,15 @@ uv run excelbench html # Generate fidelity-vs-throughput scatter plots uv run excelbench scatter +# Run template-mutation suite (wall time, RSS, preservation) +uv run excelbench mutation --output results/mutation + +# Run formula-recalculation tier (cache-free fixture, LibreOffice oracle) +uv run excelbench calc --output results/calc + +# Run cross-language context snapshot (POI/Excelize/zavora when built) +uv run excelbench cross-language-context --output results-cross-language + # Lint + typecheck uv run ruff check uv run mypy diff --git a/METHODOLOGY.md b/METHODOLOGY.md index 32ba4bc..82fcccc 100644 --- a/METHODOLOGY.md +++ b/METHODOLOGY.md @@ -28,6 +28,15 @@ This allows reliable local verification while keeping CI runnable. Two fixture paths exist: - `fixtures/excel/` (tracked): **canonical Excel-generated files** used in CI. - `fixtures/excel_xls/` (tracked): **canonical .xls fixtures** for legacy format testing. +- `fixtures/excel/tier4/` (tracked): **openpyxl-structural Tier 4 fixtures** (sheet + protection, page setup, chart anchoring). Generated by + `scripts/build_tier4_fixtures.py`; expectations are verifier-grade openpyxl + readbacks, marked `generator: openpyxl-structural` in the manifest notes. +- `fixtures/mutation/` (tracked): corporate-model template + mutation manifest for + the template-mutation lane (`scripts/build_mutation_template.py`). +- `fixtures/calc/` (tracked): **cache-free** formula fixture plus LibreOffice-oracle + expected values (`scripts/build_calc_fixture.py`). The fixture must never ship + cached formula values; the builder asserts this and fails loudly. - `test_files/` (gitignored): local scratch output for development. Generate canonical fixtures with: @@ -46,10 +55,13 @@ Features are organized into tiers reflecting complexity: | **Tier 1** (Formatting) | alignment, background_colors, borders, dimensions, number_formats, text_formatting | 6 | | **Tier 2** (Advanced) | comments, conditional_formatting, data_validation, freeze_panes, hyperlinks, images, merged_cells, pivot_tables | 8 | | **Tier 3** (Workbook Metadata) | named_ranges, tables | 2 | +| **Tier 4** (Production surfaces, 2026-09-08) | chart_anchor, page_setup, sheet_protection | 3 | -**Framework coverage:** 19 modeled features total. -**Fresh release snapshot:** 19 tested features, where 18 are scoreable per-library in -the 2026-04-29 wheel-backed WolfXL 2.0 rerun (pivot_tables is tested but N/A across adapters on macOS fixtures). +**Framework coverage:** 22 modeled features total. +**2026-04-29 release snapshot:** 19 tested features, 18 scoreable (pivot_tables N/A on macOS fixtures). +**2026-09-08 competitor snapshot:** all 22 features scored; Tier 4 fixtures are +openpyxl-structural (see Fixtures Policy), so Tier 4 expectations encode openpyxl +semantics, not Excel-authored ground truth. ## Scoring @@ -81,3 +93,33 @@ uv run excelbench report --input results/xlsx/results.json --output results/xlsx - **Secondary tables** can include cross-language libraries such as Apache POI, ClosedXML, Excelize, and ExcelJS. - Cross-language results should be labeled as ecosystem context unless the report is explicitly cross-language-focused. - The current rollout plan for the first two cross-language candidates lives in `docs/trackers/apache-poi-excelize-rollout-plan.md`. + +## Mutation Lane + +`excelbench mutation` measures surgical template editing: each engine changes two +cells in `fixtures/mutation/template_corporate_model.xlsx` in an isolated +subprocess and saves the result. + +- **Wall time**: median over `--repeats` (default 3) subprocess runs. +- **Peak RSS**: median subprocess peak resident set size. +- **Preservation score**: fraction of original package parts retained after the + edit, minus damage penalties; outputs must reopen cleanly with the openpyxl + verifier or the engine is marked `integrity-failed` with score 0. + +Preservation is a structural proxy (ZIP part inventory), not a semantic +equivalence claim. Cite wall time and preservation together. + +## Calculation Lane + +`excelbench calc` measures formula recalculation against +`fixtures/calc/expected_values.json` (133 formula cells, LibreOffice headless +oracle, oracle version pinned in the artifact). + +- The fixture ships **no cached formula values**; an engine only scores by + producing values itself. Cache passthrough cannot score (DEC-026). +- Status semantics are strict: `passed` requires a full match against the + oracle; any wrong or missing value reports `failed` with matched/total and + per-cell mismatch details. +- Formulas avoid `IFS` and `XLOOKUP` because the LibreOffice oracle build + returns `#NAME?` for them on this path; nested `IF` and INDEX/MATCH are used + instead. This constrains function coverage and is documented per artifact. diff --git a/README.md b/README.md index 880baca..91215bd 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,27 @@ Most Excel library comparisons focus on speed. ExcelBench focuses on the questio > Can this library handle my real spreadsheet without breaking the parts I care about? -ExcelBench models 19 XLSX features across 12+ Python adapters. In the fresh -wheel-backed WolfXL 2.0 release snapshot, 18 are scoreable across libraries -(pivot tables remain N/A on macOS fixtures). +ExcelBench models 22 XLSX features across 14 Python adapters plus a +cross-language context lane (Apache POI, Excelize, zavora-xlsx). Tier 4 +(sheet protection, page setup, chart anchoring) was added in the +2026-09-08 competitor snapshot. ## Results at a Glance +> Competitor snapshot: 2026-09-08 | WolfXL 2.1.0 wheel | aspose-cells-foss 26.7 | [Fidelity](results-2026-09-08/xlsx/README.md) | [Mutation](results-2026-09-08/mutation/README.md) | [Calc](results-2026-09-08/calc/README.md) | [Zavora cross-language](results-2026-09-08/cross-language/README.md) +> +> In that snapshot: openpyxl 22/22, WolfXL 19/22, aspose-cells-foss 11/22 +> green features (WolfXL 2.1.0 gaps: conditional-formatting read, +> named-range and print-title writes). +> +> Mutation suite (two-cell edit on a corporate template): WolfXL patches in +> 1.5s with 100% preservation; openpyxl and aspose rewrite at 60%; +> zavora-xlsx 0.1.2 corrupts package relationships (0%). +> +> Calc tier (133-formula financial DAG, cache-free fixture, LibreOffice +> oracle): LibreOffice 133/133, WolfXL 55/133, aspose-cells-foss 25/133, +> zavora 0/133. +> > Python release snapshot: 2026-04-29 UTC | wheel-backed WolfXL 2.0 rerun | [Fidelity](results-release-2026-04-28/README.md) | [Perf](results-release-2026-04-28/perf/README.md) | [Dashboard](results-release-2026-04-28/DASHBOARD.md) > > In that snapshot, WolfXL reaches `18/18` green features with `100%` pass rate. @@ -21,7 +36,7 @@ wheel-backed WolfXL 2.0 release snapshot, 18 are scoreable across libraries > Pivot capability lane: [separate artifact](results-cross-language-pivots/README.md) because the shipped macOS pivot fixture is not scoreable, while `excelize` can still emit pivot-bearing workbooks. > > Historical public baseline: 2026-02-17 | Excel 16.105.3 | macOS (Apple Silicon) | [Full results](results/xlsx/README.md) - +> > Newer performance snapshot: 2026-04-20 | [Perf results](results/perf/README.md) > > Read [Public Reporting Status](docs/public-reporting.md) before quoting numbers across snapshots. @@ -38,28 +53,36 @@ Cross-language libraries matter too, but for a different reason: they show how s - `Apache POI` - `Excelize` +- `zavora-xlsx` (Rust writer, added 2026-09-08) Pivot tables sit in a separate capability lane. On macOS, the shipped pivot fixture does not currently contain scoreable pivot OOXML, so the pivot story is tracked as a dedicated artifact instead of being mixed into the scored lane. See [cross-language comparison strategy](docs/trackers/cross-language-comparison-strategy.md). -## Three Lanes +## Lanes 1. **Python replacement lane** Use this when the question is: what should a Python team use instead of `openpyxl`? 2. **Cross-language context lane** -Use this when the question is: how does WolfXL compare to serious spreadsheet tooling in Java and Go? +Use this when the question is: how does WolfXL compare to serious spreadsheet tooling in Java, Go, and Rust? 3. **Pivot capability lane** Use this when the question is: can the cross-language helpers detect or emit pivot-bearing workbooks even when the main scored fixture is not valid on macOS? +4. **Template-mutation lane** +Use this when the question is: which engine can surgically edit a corporate template fastest while preserving the package? + +5. **Formula-recalculation lane** +Use this when the question is: which engine actually computes a 133-formula financial DAG from scratch (cache-free fixture, LibreOffice oracle)? + ### Library Comparison | Library | Caps | Fidelity | Read Speed | Write Speed | Modify | |---------|:----:|:--------:|:----------:|:-----------:|:------:| -| **wolfxl** | R+W | 18/18 in 2026-04-29 release snapshot | workload-specific | workload-specific | Patch | -| openpyxl | R+W | 18/18 in 2026-04-29 release snapshot | 1x (baseline per workload) | 1x (baseline per workload) | Rewrite | +| **wolfxl** | R+W | 19/22 in 2026-09-08 competitor snapshot (18/18 in 2026-04-29 snapshot) | workload-specific | workload-specific | Patch (100% preservation in mutation suite) | +| openpyxl | R+W | 22/22 in 2026-09-08 competitor snapshot | 1x (baseline per workload) | 1x (baseline per workload) | Rewrite (60% preservation in mutation suite) | +| aspose-cells-foss | R+W | 11/22 in 2026-09-08 competitor snapshot | workload-specific | workload-specific | Rewrite (60% preservation) | | xlsxwriter | W | 15/18 in 2026-04-29 release snapshot | -- | ~1x | No | | xlsxwriter-constmem | W | 12/18 in 2026-04-29 release snapshot | -- | ~2x | No | | python-calamine | R | 1/18 in 2026-04-29 release snapshot | ~1.3x | -- | No | @@ -69,13 +92,15 @@ Use this when the question is: can the cross-language helpers detect or emit piv > Speed numbers are snapshot-specific. Always cite the artifact date, workload, and profile. See [performance results](results/perf/README.md), [METHODOLOGY.md](METHODOLOGY.md), and [Public Reporting Status](docs/public-reporting.md). ### Key Findings - -- **High-fidelity libraries are rare**: in the fresh wheel-backed release snapshot, only openpyxl and WolfXL reach 18/18 green features -- **Patch modify is structurally different**: WolfXL's `load_workbook(path, modify=True)` uses surgical ZIP patching rather than a full workbook rewrite +- **High-fidelity libraries are rare**: in the 2026-04-29 release snapshot, only openpyxl and WolfXL reached 18/18 green features; in the 2026-09-08 competitor snapshot (22 features), openpyxl holds 22/22 while WolfXL 2.1.0 drops to 19/22 +- **WolfXL 2.1.0 regression signal**: conditional-formatting read scores 0 and named-range / print-title writes score 2 in the 2026-09-08 snapshot; tracked for the WolfXL repo +- **Patch modify is structurally different**: WolfXL's `load_workbook(path, modify=True)` uses surgical ZIP patching; it is the only engine reaching 100% package preservation in the mutation suite - **The abstraction tax is real**: pandas wraps openpyxl but drops from 16 to 3 green features due to DataFrame coercion (errors become NaN) - **Speed vs fidelity tradeoff is measurable**: use the perf snapshot together with the fidelity matrix rather than quoting one without the other - **Optimization modes have clear costs**: openpyxl-readonly loses 13 green features for streaming speed -- **Cross-language context is now strong too**: both `Apache POI` and `Excelize` land at `18/18` in the current scored write lane +- **Cross-language context is now strong too**: `Apache POI` and `Excelize` land at `18/18` in the scored write lane; `zavora-xlsx` 0.1.2 writes fast but corrupts hyperlink relationships on mutate and cannot recalculate +- **Calculation is a differentiator**: only LibreOffice computes the full 133-formula DAG; WolfXL 2.1.0 covers 55/133 (power-operator family returns None), aspose-cells-foss 25/133 + See the [release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md) for the fresh wheel-backed combined view, or the [historical dashboard](results/DASHBOARD.md) for the older public baseline. @@ -90,11 +115,13 @@ See the [release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md) fo ## Libraries Tested -### XLSX Profile (12 adapters) +### XLSX Profile (14 adapters) | Library | Version | Lang | Caps | Green Features | |:--------|:--------|:-----|:-----|:--------------:| -| [openpyxl](https://openpyxl.readthedocs.io/) | 3.1.5 | Python | R+W | 18/18 | +| [WolfXL](https://github.com/SynthGL/wolfxl) | 2.1.0 | Python (Rust core) | R+W | 19/22 (2026-09-08 snapshot) | +| [openpyxl](https://openpyxl.readthedocs.io/) | 3.1.5 | Python | R+W | 22/22 (2026-09-08 snapshot) | +| [aspose-cells-foss](https://pypi.org/project/aspose-cells-foss/) | 26.7 | Python (JVM-core FOSS) | R+W | 11/22 (2026-09-08 snapshot) | | [XlsxWriter](https://xlsxwriter.readthedocs.io/) | 3.2.9 | Python | W | 15/18 | | [xlsxwriter-constmem](https://xlsxwriter.readthedocs.io/) | 3.2.9 | Python | W | 12/18 | | [openpyxl-readonly](https://openpyxl.readthedocs.io/) | 3.1.5 | Python | R | 3/18 | @@ -107,6 +134,18 @@ See the [release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md) fo | [xlwt](https://github.com/python-excel/xlwt) | 1.3.0 | Python | W | 4/18 | | [xlrd](https://github.com/python-excel/xlrd) | 2.0.2 | Python | R | .xls only | +> Green-feature counts are per dated snapshot; `x/18` numbers come from the +> 2026-04-29 release snapshot and `x/22` from the 2026-09-08 competitor +> snapshot (Tier 4 added). Never mix counts across snapshots. + +### Cross-Language Context (oracle helpers) + +| Library | Version | Lang | Caps | Notes | +|:--------|:--------|:-----|:-----|:------| +| Apache POI | 5.x | Java | W | 18/18 scored write lane (2026-04-29) | +| Excelize | 2.x | Go | W | 18/18 scored write lane (2026-04-29) | +| zavora-xlsx | 0.1.2 | Rust | W | Fast writer; 0.1.2 corrupts hyperlink relationships on mutate; no recalc | + ### XLS Profile (2 adapters) | Library | Green Features | Notes | @@ -143,6 +182,7 @@ ExcelBench now ships a separate cross-language context snapshot for mature non-P - `Apache POI` (Java) - `Excelize` (Go) +- `zavora-xlsx` (Rust writer, added 2026-09-08; helper in `tools/external-oracles/zavora`) These are not framed as Python drop-in replacements. They answer a different question: how strong is WolfXL relative to serious spreadsheet tooling outside Python? @@ -214,6 +254,12 @@ uv sync # Run the benchmark against pre-built fixtures (no Excel required) uv run excelbench benchmark --tests fixtures/excel --output results +# Template-mutation suite (wall time, RSS, preservation) +uv run excelbench mutation + +# Formula-recalculation tier (cache-free fixture, LibreOffice oracle) +uv run excelbench calc + # Generate the heatmap uv run excelbench heatmap @@ -232,7 +278,7 @@ uv run excelbench generate --output fixtures/excel ## Feature Coverage -### Tested (19 features; 18 currently scoreable in the release snapshot) +### Tested (22 features) | Tier | Features | Count | |:-----|:---------|:-----:| @@ -240,16 +286,22 @@ uv run excelbench generate --output fixtures/excel | **Tier 1** -- Formatting | Text formatting, background colors, number formats, alignment, borders, dimensions | 6 | | **Tier 2** -- Advanced | Merged cells, conditional formatting, data validation, hyperlinks, images, comments, freeze panes, pivot tables | 8 | | **Tier 3** -- Workbook metadata | Named ranges, tables | 2 | +| **Tier 4** -- Production surfaces (2026-09-08) | Sheet protection, page setup, chart anchoring | 3 | > Pivot tables are tested but score N/A across all adapters in the current macOS run. -> Library green-feature scores therefore use an /18 denominator in the fresh release snapshot. +> Green-feature denominators: /18 in the 2026-04-29 release snapshot, /22 in the 2026-09-08 competitor snapshot. ### Planned -Charts, print settings, protection. +None currently queued. Tier 4 (charts anchoring, print settings, protection) shipped 2026-09-08. ## Detailed Results +- **[Competitor snapshot fidelity](results-2026-09-08/xlsx/README.md)** -- 22 features x 14 Python adapters, WolfXL 2.1.0 + aspose-cells-foss +- **[Competitor snapshot heatmap](results-2026-09-08/xlsx/heatmap.png)** ([SVG](results-2026-09-08/xlsx/heatmap.svg)) -- 22x14 visual score matrix +- **[Competitor snapshot mutation](results-2026-09-08/mutation/README.md)** -- template mutation: wall time, RSS, preservation +- **[Competitor snapshot calc](results-2026-09-08/calc/README.md)** -- 133-formula financial DAG vs LibreOffice oracle +- **[Competitor snapshot zavora cross-language](results-2026-09-08/cross-language/README.md)** -- zavora-xlsx 0.1.2 Rust writer context - **[XLSX results](results/xlsx/README.md)** -- per-library, per-test-case breakdowns with tier list - **[Release snapshot results](results-release-2026-04-28/README.md)** -- fresh wheel-backed WolfXL 2.0 rerun - **[XLS results](results/xls/README.md)** -- legacy format results diff --git a/TRACKER.md b/TRACKER.md index 7f432d5..5615c73 100644 --- a/TRACKER.md +++ b/TRACKER.md @@ -4,7 +4,7 @@ > self-contained sprint (one branch, one PR, one row flip). Resume cold by reading this file > and the most recent `[*INCOMPLETE*]` marker. -**Last updated**: 2026-04-27 (S3 shipped) +**Last updated**: 2026-09-08 (competitor snapshot landed; S4+ perf sprints still queued) ## Status Table @@ -17,6 +17,7 @@ | S5 | Workbook complexity perf | Planned | M (1 wk) | `feat/perf-complexity` | — | — | | S6 | Cold-start / warm path | Planned | S (3–5 d) | `feat/perf-cold-start` | — | — | | S7 | Round-trip fidelity (LibreOffice) | Planned | L (~2 wk) | `feat/fidelity-roundtrip` | — | — | +| C1 | Competitor snapshot: aspose-foss + zavora adapters, Tier 4, mutation + calc lanes | Shipped (branch) | L | `feat/competitor-snapshot-2026-09` | — | this branch | **Status legend**: `Planned` → `In Progress` → `Shipped` (or `Blocked` with reason). @@ -182,3 +183,26 @@ Use this template when appending to **Acceptance Notes** below. - Decisions: [`decisions.md`](decisions.md) - Key seams: `src/excelbench/perf/runner.py`, `src/excelbench/harness/adapters/base.py`, `src/excelbench/results/html_dashboard.py`. + +## Session Log: Competitor Snapshot (2026-09-08) + +Branch `feat/competitor-snapshot-2026-09` (this branch). + +**Shipped**: +- `aspose-cells-foss` adapter (Python lane, `aspose` extra) — 11/22 green. +- `zavora-xlsx` external oracle adapter (cross-language lane) + Rust helper in + `tools/external-oracles/zavora`. +- Tier 4 features: sheet_protection, page_setup, chart_anchor (22 scored + features), openpyxl-structural fixtures. +- wolfxl adapter ported to WolfXL 2.1.0 public API (19/22; CF read 0, + named-range/print-title writes 2). +- Template-mutation lane (`excelbench mutation`): wolfxl 100% preservation; + openpyxl/aspose 60%; zavora 0.1.2 integrity-failed. +- Calc tier (`excelbench calc`): cache-free 133-formula fixture, LibreOffice + oracle; LO 133/133, wolfxl 55/133 (power-operator family returns None), + aspose 25/133, zavora 0/133. +- Snapshot artifacts: `results-2026-09-08/{xlsx,mutation,calc,cross-language}`. +- Decisions DEC-023..DEC-026. + +**Verification**: full pytest suite + ruff on this branch (see PR body for +exact receipts). diff --git a/architecture.md b/architecture.md index 82b9d95..c270295 100644 --- a/architecture.md +++ b/architecture.md @@ -76,15 +76,23 @@ Most-touched top-level directories: - `harness/roundtrip_runner.py`: open/save idempotence context lane - `harness/compat_cases.py`: openpyxl-style compatibility snippet lane - `harness/artifact_context.py`: chart and macro package evidence lanes + - `harness/mutation.py`: template-mutation lane (subprocess wall time, RSS, + package-preservation scoring) + - `harness/calc.py`: formula-recalculation tier engines (wolfxl, LibreOffice, + aspose-cells-foss, zavora oracle) against the cache-free fixture + - `modifiable.py`: engine registry for mutation-capable adapters - `harness/external_fixture_specs/`: tool-specific external oracle fixture definitions imported by the fixture-pack generator - `perf/`: performance runner + renderer - `results/`: fidelity result renderers (md/csv) + dashboards/plots - `fixtures/` - - `excel/`: canonical .xlsx fixtures (git-tracked, Excel-generated) + - `excel/`: canonical .xlsx fixtures (git-tracked; tiers 0-3 Excel-generated, + `excel/tier4/` openpyxl-structural) - `excel_xls/`: canonical .xls fixtures - `throughput_xlsx/`: scale fixtures for perf/throughput workloads + - `mutation/`: corporate-model template + mutation manifest + - `calc/`: cache-free formula fixture + LibreOffice oracle expected values - `tools/external-oracles/` - Optional subprocess helpers for non-Python oracle tools. @@ -100,6 +108,8 @@ Most-touched top-level directories: merges, freeze panes, and sheet protection. - `closedxml/`: .NET helper that generates workbooks with ClosedXML tables, pivots, and conditional formatting. + - `zavora/`: Rust helper (zavora-xlsx) for write/mutate/calculate oracle + operations over the stdin/stdout JSON contract. - `npoi/`: .NET helper that generates POI-style workbooks with NPOI formulas, comments, rich text, merged ranges, and sheet protection. diff --git a/decisions.md b/decisions.md index c74dc0d..f8ffe66 100644 --- a/decisions.md +++ b/decisions.md @@ -40,6 +40,141 @@ Skip logging for routine bug fixes, refactors, or incremental test additions. ## Decisions +### DEC-023 — Tier-4 fidelity features via openpyxl-structural fixtures (2026-09-08) + +**Context**: The scored matrix stopped at 19 features. Sheet protection, page +setup, and chart anchoring are recurring production surfaces with no +cross-library comparison, and this workstation has no Excel app to author +authoritative fixtures. + +**Decision**: + +- Add three Tier-4 features: `sheet_protection`, `page_setup`, + `chart_anchor` (22 scored features total). +- Fixtures are built by `scripts/build_tier4_fixtures.py` with openpyxl and + marked `generator: openpyxl-structural` in the manifest notes; expected + values are full adapter readbacks from the verifier-grade openpyxl + implementation, not Excel screenshots. +- Raw OOXML semantics are pinned in `adapters/base.py` optional methods + (protection attribute True = BLOCKED; `fit_to_height=None` when only + `fit_to_width` is set; chart anchors are two-cell `from`/`to` only). +- Write-only keys that no reader can verify (`password`, + `data_ref`/`categories_ref`) ride in the manifest and are stripped before + comparison, following the `_strip_cf_priority` precedent. + +**Alternatives considered**: + +1. Excel-authored fixtures - unavailable on this machine; would also block + CI reproduction. +2. Skip the features until Excel access exists - rejected; the features are + structural and openpyxl is the de-facto Python semantic reference. + +**Consequences**: + +- Tier-4 expectations encode openpyxl's semantics, not Excel's. Any future + Excel-authored evidence that disagrees becomes a documented fixture + revision, not a silent change. +- Most read-optimized adapters score 0 on Tier-4 by design (structured + unsupported failures), which is the correct public signal. + +### DEC-024 — Competitor adapters: aspose-cells-foss (Python lane) and zavora-xlsx (cross-language) (2026-09-08) + +**Context**: The public matrix lacked two comparison points users ask for: +Aspose's FOSS Python offering and a fast Rust writer (zavora-xlsx). + +**Decision**: + +- `aspose-cells-foss` joins the Python lane behind the `aspose` extra + (`aspose-cells-foss>=26.7`), availability-gated so installs without the + extra lose nothing. +- `zavora-xlsx` joins the cross-language lane only + (`CROSS_LANGUAGE_ADAPTER_NAMES`) via the DEC-021 external-oracle subprocess + contract; a Rust helper lives in `tools/external-oracles/zavora`. +- Both adapters raise structured `UnsupportedAdapterOperationError` for + unsupported operations; no silent passes. + +**Alternatives considered**: + +1. Put zavora in the Python lane - rejected; it is not a Python library and + would blur the Python-first decision surface. +2. Skip aspose FOSS due to missing pivots/chart rendering - rejected; its + 11/22 with explicit gaps is exactly the comparison signal the matrix needs. + +**Consequences**: + +- The Python lane grows to 14 adapters; the main snapshot stays Python-only. +- Upstream zavora-xlsx 0.1.2 defects (hyperlink relationship corruption on + mutate/save, `recalculate()` returning null caches) become visible, scored + findings rather than hidden skips. + +### DEC-025 — Template-mutation suite: wall time, RSS, preservation score (2026-09-08) + +**Context**: Modify workloads were only measurable via WolfXL's patch path in +perf lanes. Real corporate deliverables are mutated templates: change two +cells, save, keep everything else comparable. + +**Decision**: + +- Add `excelbench mutation` running surgical two-cell mutations on + `fixtures/mutation/template_corporate_model.xlsx` (built by + `scripts/build_mutation_template.py`; styles, CF, named ranges, hyperlinks, + data validation, multiple sheets). +- Score three axes per engine: median wall time over repeats, peak RSS, and a + package-preservation score (retained parts minus damage penalties). +- Engines: openpyxl, wolfxl (`modify=True`), aspose-cells-foss, zavora-xlsx + oracle mutate. Integrity failure (output cannot be reopened by the + verifier) scores 0 and is labeled `integrity-failed`, not silently skipped. + +**Alternatives considered**: + +1. Fold into perf lanes - rejected; perf lanes are cell-throughput oriented + and have no preservation axis. +2. Byte-identical diff as the score - rejected; ZIP timestamps make byte + equality meaningless. Structural part retention is the honest proxy. + +**Consequences**: + +- Preservation is a structural proxy, not a semantic one. The verifier + reopens outputs with openpyxl to catch the failure class that matters + (corrupt relationships, as zavora 0.1.2 demonstrates). + +### DEC-026 — Calc tier: cache-free fixture, LibreOffice oracle, strict status semantics (2026-09-08) + +**Context**: Formula recalculation had no lane. The first builder draft +shipped LibreOffice-computed caches inside the fixture itself, which let +cache-passthrough engines score a perfect 133/133 without calculating +anything (zavora 0.1.2 preserves input caches on save). + +**Decision**: + +- The canonical fixture `fixtures/calc/financial_model.xlsx` ships formulas + with NO cached values; the builder asserts cache-freedom and fails loudly + otherwise. +- Oracle values are harvested from a throwaway LibreOffice headless + recalculation copy (`expected_values.json`, 133 cells, oracle version + pinned). +- An engine that runs but scores below the oracle total reports `failed` + with matched/total; only a full match is `passed`. Missing-value + mismatches are counted separately from wrong-value mismatches. +- Nested `IF` is used instead of `IFS` (LibreOffice returns `#NAME?` on this + path); XLOOKUP is omitted for the same reason. + +**Alternatives considered**: + +1. Keep cached fixture and accept passthrough - rejected; it scores + file-copying, not calculation. +2. Excel as oracle - unavailable on this machine. + +**Consequences**: + +- Honest first snapshot: LibreOffice 133/133; wolfxl 55/133 (its calculator + returns None for the `^` power-operator formula family and dependents); + aspose-cells-foss 25/133 (FOSS FormulaEvaluator has no value for 107 + formulas); zavora 0.1.2 0/133 (writes no caches). +- Cache-free fixtures make engines without write-back caches look strictly + worse; that is the intended signal, documented here. + + ### DEC-022 — Semantic diff and context lanes stay additive (2026-04-29) **Context**: ExcelBench needed better evidence for workbook drift, roundtrip diff --git a/docs/public-reporting.md b/docs/public-reporting.md index d44a6ff..3c080a6 100644 --- a/docs/public-reporting.md +++ b/docs/public-reporting.md @@ -31,6 +31,10 @@ This page explains what the current ExcelBench repo artifacts mean and how to ci | `results-release-2026-04-28/perf/README.md` | 2026-04-29 | Matching wheel-backed performance rerun | | `results-cross-language/README.md` | 2026-04-29 | Checked-in cross-language context snapshot for Apache POI and Excelize | | `results-cross-language-pivots/README.md` | 2026-04-29 | Separate pivot capability artifact for cross-language helpers | +| `results-2026-09-08/xlsx/README.md` | 2026-09-08 | Competitor fidelity snapshot: 22 features, 14 Python adapters, WolfXL 2.1.0 + aspose-cells-foss | +| `results-2026-09-08/mutation/README.md` | 2026-09-08 | Template-mutation lane (wall time, RSS, preservation) | +| `results-2026-09-08/calc/README.md` | 2026-09-08 | Formula-recalculation tier vs LibreOffice oracle on a cache-free fixture | +| `results-2026-09-08/cross-language/README.md` | 2026-09-08 | zavora-xlsx 0.1.2 Rust writer cross-language context | ## Safe Claims Right Now @@ -40,6 +44,8 @@ This page explains what the current ExcelBench repo artifacts mean and how to ci - The fresh WolfXL 2.0 wheel-backed release snapshot is available separately from the older historical baseline. - A separate cross-language context snapshot is available for ecosystem positioning and should be cited as a separate lane from the Python hero table. - A separate pivot capability artifact is available for cross-language helpers and should be cited as a capability note, not as a scored lane. +- The 2026-09-08 competitor snapshot extends the scored matrix to 22 features (Tier 4 is openpyxl-structural, not Excel-authored) and adds aspose-cells-foss; its fidelity numbers must not be mixed with /18 denominators from earlier snapshots. +- The mutation and calc lanes are separate decision surfaces (modify-integrity and calculation correctness) and must be cited as their own artifacts, never folded into feature-parity claims. ## Claims That Need Fresh Reruns diff --git a/fixtures/calc/expected_values.json b/fixtures/calc/expected_values.json new file mode 100644 index 0000000..3daf8de --- /dev/null +++ b/fixtures/calc/expected_values.json @@ -0,0 +1,537 @@ +{ + "cells": { + "Schedule!B10": { + "type": "number", + "value": 0.0 + }, + "Schedule!B11": { + "type": "number", + "value": -308872.0 + }, + "Schedule!B2": { + "type": "number", + "value": 100000.0 + }, + "Schedule!B3": { + "type": "number", + "value": 38000.0 + }, + "Schedule!B4": { + "type": "number", + "value": 62000.0 + }, + "Schedule!B5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!B6": { + "type": "number", + "value": 488.0 + }, + "Schedule!B7": { + "type": "number", + "value": 719.0 + }, + "Schedule!B8": { + "type": "number", + "value": 400872.0 + }, + "Schedule!B9": { + "type": "number", + "value": -300872.0 + }, + "Schedule!C10": { + "type": "number", + "value": 0.0 + }, + "Schedule!C11": { + "type": "number", + "value": -306442.0 + }, + "Schedule!C2": { + "type": "number", + "value": 104500.0 + }, + "Schedule!C3": { + "type": "number", + "value": 39710.0 + }, + "Schedule!C4": { + "type": "number", + "value": 64790.0 + }, + "Schedule!C5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!C6": { + "type": "number", + "value": 488.0 + }, + "Schedule!C7": { + "type": "number", + "value": 719.0 + }, + "Schedule!C8": { + "type": "number", + "value": 402582.0 + }, + "Schedule!C9": { + "type": "number", + "value": -298082.0 + }, + "Schedule!D10": { + "type": "number", + "value": 0.0 + }, + "Schedule!D11": { + "type": "number", + "value": -303902.65 + }, + "Schedule!D2": { + "type": "number", + "value": 109202.5 + }, + "Schedule!D3": { + "type": "number", + "value": 41496.95 + }, + "Schedule!D4": { + "type": "number", + "value": 67705.55 + }, + "Schedule!D5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!D6": { + "type": "number", + "value": 488.0 + }, + "Schedule!D7": { + "type": "number", + "value": 719.0 + }, + "Schedule!D8": { + "type": "number", + "value": 404368.95 + }, + "Schedule!D9": { + "type": "number", + "value": -295166.45 + }, + "Schedule!E10": { + "type": "number", + "value": 0.0 + }, + "Schedule!E11": { + "type": "number", + "value": -301249.02925 + }, + "Schedule!E2": { + "type": "number", + "value": 114116.6125 + }, + "Schedule!E3": { + "type": "number", + "value": 43364.31275 + }, + "Schedule!E4": { + "type": "number", + "value": 70752.29975 + }, + "Schedule!E5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!E6": { + "type": "number", + "value": 488.0 + }, + "Schedule!E7": { + "type": "number", + "value": 719.0 + }, + "Schedule!E8": { + "type": "number", + "value": 406236.31275 + }, + "Schedule!E9": { + "type": "number", + "value": -292119.70025 + }, + "Schedule!F10": { + "type": "number", + "value": 0.0 + }, + "Schedule!F11": { + "type": "number", + "value": -298475.99556625 + }, + "Schedule!F2": { + "type": "number", + "value": 119251.8600625 + }, + "Schedule!F3": { + "type": "number", + "value": 45315.70682375 + }, + "Schedule!F4": { + "type": "number", + "value": 73936.15323875 + }, + "Schedule!F5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!F6": { + "type": "number", + "value": 488.0 + }, + "Schedule!F7": { + "type": "number", + "value": 719.0 + }, + "Schedule!F8": { + "type": "number", + "value": 408187.70682375 + }, + "Schedule!F9": { + "type": "number", + "value": -288935.84676125 + }, + "Schedule!G10": { + "type": "number", + "value": 0.0 + }, + "Schedule!G11": { + "type": "number", + "value": -295578.175366731 + }, + "Schedule!G2": { + "type": "number", + "value": 124618.193765312 + }, + "Schedule!G3": { + "type": "number", + "value": 47354.9136308187 + }, + "Schedule!G4": { + "type": "number", + "value": 77263.2801344937 + }, + "Schedule!G5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!G6": { + "type": "number", + "value": 488.0 + }, + "Schedule!G7": { + "type": "number", + "value": 719.0 + }, + "Schedule!G8": { + "type": "number", + "value": 410226.913630819 + }, + "Schedule!G9": { + "type": "number", + "value": -285608.719865506 + }, + "Schedule!H10": { + "type": "number", + "value": 0.0 + }, + "Schedule!H11": { + "type": "number", + "value": -292549.953258234 + }, + "Schedule!H2": { + "type": "number", + "value": 130226.012484752 + }, + "Schedule!H3": { + "type": "number", + "value": 49485.8847442056 + }, + "Schedule!H4": { + "type": "number", + "value": 80740.127740546 + }, + "Schedule!H5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!H6": { + "type": "number", + "value": 488.0 + }, + "Schedule!H7": { + "type": "number", + "value": 719.0 + }, + "Schedule!H8": { + "type": "number", + "value": 412357.884744206 + }, + "Schedule!H9": { + "type": "number", + "value": -282131.872259454 + }, + "Schedule!I10": { + "type": "number", + "value": 0.0 + }, + "Schedule!I11": { + "type": "number", + "value": -289385.461154855 + }, + "Schedule!I2": { + "type": "number", + "value": 136086.183046565 + }, + "Schedule!I3": { + "type": "number", + "value": 51712.7495576948 + }, + "Schedule!I4": { + "type": "number", + "value": 84373.4334888705 + }, + "Schedule!I5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!I6": { + "type": "number", + "value": 488.0 + }, + "Schedule!I7": { + "type": "number", + "value": 719.0 + }, + "Schedule!I8": { + "type": "number", + "value": 414584.749557695 + }, + "Schedule!I9": { + "type": "number", + "value": -278498.56651113 + }, + "Schedule!J10": { + "type": "number", + "value": 0.0 + }, + "Schedule!J11": { + "type": "number", + "value": -286078.566906823 + }, + "Schedule!J2": { + "type": "number", + "value": 142210.061283661 + }, + "Schedule!J3": { + "type": "number", + "value": 54039.8232877911 + }, + "Schedule!J4": { + "type": "number", + "value": 88170.2379958697 + }, + "Schedule!J5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!J6": { + "type": "number", + "value": 488.0 + }, + "Schedule!J7": { + "type": "number", + "value": 719.0 + }, + "Schedule!J8": { + "type": "number", + "value": 416911.823287791 + }, + "Schedule!J9": { + "type": "number", + "value": -274701.76200413 + }, + "Schedule!K10": { + "type": "number", + "value": 0.0 + }, + "Schedule!K11": { + "type": "number", + "value": -282622.86241763 + }, + "Schedule!K2": { + "type": "number", + "value": 148609.514041425 + }, + "Schedule!K3": { + "type": "number", + "value": 56471.6153357417 + }, + "Schedule!K4": { + "type": "number", + "value": 92137.8987056838 + }, + "Schedule!K5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!K6": { + "type": "number", + "value": 488.0 + }, + "Schedule!K7": { + "type": "number", + "value": 719.0 + }, + "Schedule!K8": { + "type": "number", + "value": 419343.615335742 + }, + "Schedule!K9": { + "type": "number", + "value": -270734.101294316 + }, + "Schedule!L10": { + "type": "number", + "value": 0.0 + }, + "Schedule!L11": { + "type": "number", + "value": -279011.651226424 + }, + "Schedule!L2": { + "type": "number", + "value": 155296.94217329 + }, + "Schedule!L3": { + "type": "number", + "value": 59012.8380258501 + }, + "Schedule!L4": { + "type": "number", + "value": 96284.1041474396 + }, + "Schedule!L5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!L6": { + "type": "number", + "value": 488.0 + }, + "Schedule!L7": { + "type": "number", + "value": 719.0 + }, + "Schedule!L8": { + "type": "number", + "value": 421884.83802585 + }, + "Schedule!L9": { + "type": "number", + "value": -266587.89585256 + }, + "Schedule!M10": { + "type": "number", + "value": 0.0 + }, + "Schedule!M11": { + "type": "number", + "value": -275237.935531613 + }, + "Schedule!M2": { + "type": "number", + "value": 162285.304571088 + }, + "Schedule!M3": { + "type": "number", + "value": 61668.4157370133 + }, + "Schedule!M4": { + "type": "number", + "value": 100616.888834074 + }, + "Schedule!M5": { + "type": "number", + "value": 12000.0 + }, + "Schedule!M6": { + "type": "number", + "value": 488.0 + }, + "Schedule!M7": { + "type": "number", + "value": 719.0 + }, + "Schedule!M8": { + "type": "number", + "value": 424540.415737013 + }, + "Schedule!M9": { + "type": "number", + "value": -262255.111165926 + }, + "Summary!B10": { + "type": "number", + "value": -2021215.15613594 + }, + "Summary!B11": { + "type": "number", + "value": 0.213327377 + }, + "Summary!B12": { + "type": "number", + "value": 45777.0 + }, + "Summary!B13": { + "type": "number", + "value": 45777.0 + }, + "Summary!B14": { + "type": "number", + "value": 16.0 + }, + "Summary!B15": { + "type": "number", + "value": 4.0 + }, + "Summary!B2": { + "type": "number", + "value": 0.0 + }, + "Summary!B3": { + "type": "number", + "value": 2.0 + }, + "Summary!B4": { + "type": "number", + "value": -300872.0 + }, + "Summary!B5": { + "type": "number", + "value": -262255.111165926 + }, + "Summary!B6": { + "type": "number", + "value": -293283.86 + }, + "Summary!B7": { + "type": "number", + "value": 20.0 + }, + "Summary!B8": { + "type": "number", + "value": 125.25 + } + }, + "oracle": "libreoffice/LibreOffice 26.8.0.3 bce0998afefdbc355585ca324285661a2170ba77" +} diff --git a/fixtures/calc/financial_model.xlsx b/fixtures/calc/financial_model.xlsx new file mode 100644 index 0000000..64efb66 Binary files /dev/null and b/fixtures/calc/financial_model.xlsx differ diff --git a/fixtures/excel/manifest.json b/fixtures/excel/manifest.json index 6e19e92..59f0d32 100644 --- a/fixtures/excel/manifest.json +++ b/fixtures/excel/manifest.json @@ -1556,6 +1556,183 @@ "importance": "edge" } ] + }, + { + "path": "tier4/20_sheet_protection.xlsx", + "feature": "sheet_protection", + "tier": 4, + "file_format": "xlsx", + "test_cases": [ + { + "id": "prot_basic", + "label": "Protection: basic (OOXML defaults)", + "row": 2, + "sheet": "sheet_protection_basic", + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "importance": "basic" + }, + { + "id": "prot_password", + "label": "Protection: with password hash", + "row": 2, + "sheet": "sheet_protection_password", + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "importance": "basic" + }, + { + "id": "prot_granular", + "label": "Protection: granular attribute flags", + "row": 2, + "sheet": "sheet_protection_granular", + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "importance": "edge" + } + ] + }, + { + "path": "tier4/21_page_setup.xlsx", + "feature": "page_setup", + "tier": 4, + "file_format": "xlsx", + "test_cases": [ + { + "id": "page_setup_landscape", + "label": "Page setup: landscape + fit-to-width", + "row": 2, + "sheet": "page_setup_landscape", + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "importance": "basic" + }, + { + "id": "page_setup_scale", + "label": "Page setup: portrait at 75% scale", + "row": 2, + "sheet": "page_setup_scale", + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "importance": "basic" + }, + { + "id": "page_setup_titles", + "label": "Page setup: print titles + header/footer", + "row": 2, + "sheet": "page_setup_titles", + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "importance": "edge" + } + ] + }, + { + "path": "tier4/22_chart_anchor.xlsx", + "feature": "chart_anchor", + "tier": 4, + "file_format": "xlsx", + "test_cases": [ + { + "id": "chart_bar", + "label": "Chart: bar with twoCell anchor", + "row": 2, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "importance": "basic" + }, + { + "id": "chart_line", + "label": "Chart: line with twoCell anchor", + "row": 2, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "importance": "edge" + } + ] } - ] -} \ No newline at end of file + ], + "notes": { + "tier4_generator": "openpyxl-structural", + "tier4_generated_at": "2026-09-08T05:26:38.636308+00:00", + "tier4_excel_version": "none" + } +} diff --git a/fixtures/excel/tier4/20_sheet_protection.xlsx b/fixtures/excel/tier4/20_sheet_protection.xlsx new file mode 100644 index 0000000..7cbfb7c Binary files /dev/null and b/fixtures/excel/tier4/20_sheet_protection.xlsx differ diff --git a/fixtures/excel/tier4/21_page_setup.xlsx b/fixtures/excel/tier4/21_page_setup.xlsx new file mode 100644 index 0000000..837a863 Binary files /dev/null and b/fixtures/excel/tier4/21_page_setup.xlsx differ diff --git a/fixtures/excel/tier4/22_chart_anchor.xlsx b/fixtures/excel/tier4/22_chart_anchor.xlsx new file mode 100644 index 0000000..1e73e3f Binary files /dev/null and b/fixtures/excel/tier4/22_chart_anchor.xlsx differ diff --git a/fixtures/mutation/manifest.json b/fixtures/mutation/manifest.json new file mode 100644 index 0000000..45d5f46 --- /dev/null +++ b/fixtures/mutation/manifest.json @@ -0,0 +1,64 @@ +{ + "checksums": { + "[Content_Types].xml": "513f5b1379467cfce8af0023ec5b41a0ed48f178468fd253854baeedc662958a", + "_rels/.rels": "642a28a5f2aa30def33495e94ec4a22e24d944c79b4432810068ea96eec19557", + "customXml/_rels/item1.xml.rels": "de414e07e13d417dd48d2d631af4575e3c6691dfa601a5e1b489d1975cd8e1d8", + "customXml/item1.xml": "e9add2e6b47913324315bf91125bcce244eee364ba11ec00803e226674fe35b1", + "customXml/itemProps1.xml": "de62706849294a697ecf047953b54c0183a264d5226ef3f43cf3ce47d2ee3662", + "docProps/app.xml": "209fca6b00afe72a5029754b94be5953d8f16d96f67130325566b9366ad4ccc5", + "docProps/core.xml": "1c9e31d7cf7baceb04f5faa336474660ba29c65b98bb2f432c095844125e5c59", + "xl/_rels/workbook.xml.rels": "9f80b92319d8b9c20f25d718624b941fcbb42403a9f86fe137722889b35d4b87", + "xl/charts/chart1.xml": "54c98567bbe1b8340e8e0cd4dac37b07ed37a4fedf59832db1ef04499daf0eaf", + "xl/charts/chart2.xml": "2c793da99c3bcf4e2f96daad7ae96f14be96703e1c5cb243255767e844d29f59", + "xl/comments/comment1.xml": "9ecdd9e0bbfe8419b131ec4a3ddcb3dead0b5b2bfa7b5cacec67b2366048e07d", + "xl/drawings/_rels/drawing1.xml.rels": "e777fb5fa444e92869fb4a921dfc82a345d778e53d0651cdbe23ecc95f18820a", + "xl/drawings/commentsDrawing1.vml": "5332c3e7f0d4cfba5474cc0f363a7ef117f577bae63b1baf45db9405c45f3c4c", + "xl/drawings/drawing1.xml": "57b54458ba4f3154d99c1eef6a2c3e40f4b87672aa32c3a169a9adcdbb77c3d9", + "xl/styles.xml": "b2a6bff8de4ab9f2b679067e6a5c8afb6f50abd7c3c7d4e75a35623ecf158eac", + "xl/tables/table1.xml": "58187f247861262791e5f126dddb9980b1029fe58509ec7531cc79018fc36230", + "xl/theme/theme1.xml": "d15e8ebf78ef7b9720839d7ae8fdc81a7df5bc24706d8e137df61a5683c358d9", + "xl/workbook.xml": "a85ba3be52d11f3e140efdf826d1f41cc7ec43bbf7a1adfe87587b9a817fa06d", + "xl/worksheets/_rels/sheet1.xml.rels": "518c7cac0ab053f3fdfb75c685b4fc48fe17da185b0586141fdf21cdcc795178", + "xl/worksheets/_rels/sheet3.xml.rels": "0043881ca7f803da685c9fc201bc7c04f045356813c7b94a5d00253d3b5df9ee", + "xl/worksheets/sheet1.xml": "b3ff1bcaacacc9c5ed993316c5f39db26edf6d9616eccfcacbb8ac15420e7dd6", + "xl/worksheets/sheet2.xml": "487cfc0dc5c698b45a7fde75f88e9a70ed26665a23be7b541068de8e883ecd38", + "xl/worksheets/sheet3.xml": "00eab034ea7eae39937d766b98a88a1555e691a3c4f6a800ee67ba4fd3aeb39d" + }, + "generated_at": "2026-01-01T00:00:00Z", + "generator": "openpyxl-structural+customxml-injection", + "mutation": { + "cell": "B2", + "sheet": "Inputs", + "value": "MUTATED-" + }, + "parts": [ + "[Content_Types].xml", + "_rels/.rels", + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml", + "docProps/app.xml", + "docProps/core.xml", + "xl/_rels/workbook.xml.rels", + "xl/charts/chart1.xml", + "xl/charts/chart2.xml", + "xl/comments/comment1.xml", + "xl/drawings/_rels/drawing1.xml.rels", + "xl/drawings/commentsDrawing1.vml", + "xl/drawings/drawing1.xml", + "xl/styles.xml", + "xl/tables/table1.xml", + "xl/theme/theme1.xml", + "xl/workbook.xml", + "xl/worksheets/_rels/sheet1.xml.rels", + "xl/worksheets/_rels/sheet3.xml.rels", + "xl/worksheets/sheet1.xml", + "xl/worksheets/sheet2.xml", + "xl/worksheets/sheet3.xml" + ], + "second_mutation": { + "cell": "C3", + "sheet": "Inputs", + "value": 1337 + } +} diff --git a/fixtures/mutation/template_corporate_model.xlsx b/fixtures/mutation/template_corporate_model.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/fixtures/mutation/template_corporate_model.xlsx differ diff --git a/pyproject.toml b/pyproject.toml index 4c97efb..ad38bfb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,9 @@ docs = [ "mkdocs-minify-plugin>=0.7", "pymdown-extensions>=10.0", ] +aspose = [ + "aspose-cells-foss>=26.7", +] [project.scripts] excelbench = "excelbench.cli:app" @@ -121,6 +124,10 @@ module = [ "plotly", "plotly.*", "numpy.*", + "aspose", + "aspose.*", + "aspose.cells_foss", + "aspose.cells_foss.*", "pyumya", "pyumya.*", ] diff --git a/results-2026-09-08/calc/README.md b/results-2026-09-08/calc/README.md new file mode 100644 index 0000000..5b6c97c --- /dev/null +++ b/results-2026-09-08/calc/README.md @@ -0,0 +1,18 @@ +# ExcelBench Formula Recalculation Results + +Oracle: libreoffice/LibreOffice 26.8.0.3 bce0998afefdbc355585ca324285661a2170ba77 + +Formula values are compared with absolute tolerance 1e-6 or relative tolerance 1e-9 for numbers; strings and booleans compare exactly. + +| Engine | Status | Matched/total | First mismatches | +| --- | --- | --- | --- | +| wolfxl | failed | 55/133 | Schedule!B11: expected -308872.0, actual None
Schedule!B2: expected 100000.0, actual None
Schedule!B3: expected 38000.0, actual None
Schedule!B4: expected 62000.0, actual None
Schedule!B8: expected 400872.0, actual None
Schedule!B9: expected -300872.0, actual None
Schedule!C11: expected -306442.0, actual None
Schedule!C2: expected 104500.0, actual None
Schedule!C3: expected 39710.0, actual None
Schedule!C4: expected 64790.0, actual None | + +wolfxl: 78/133 formula values wrong or missing (first mismatch batch: 10 shown, 10 missing, 0 wrong) +| libreoffice | passed | 133/133 | — | +| aspose_cells_foss | failed | 25/133 | Schedule!B11: expected -308872.0, actual None
Schedule!B2: expected 100000.0, actual None
Schedule!B3: expected 38000.0, actual None
Schedule!B4: expected 62000.0, actual None
Schedule!B6: expected 488.0, actual None
Schedule!B7: expected 719.0, actual None
Schedule!B8: expected 400872.0, actual None
Schedule!B9: expected -300872.0, actual None
Schedule!C11: expected -306442.0, actual None
Schedule!C2: expected 104500.0, actual None | + +aspose_cells_foss: FOSS FormulaEvaluator returned no value for 107 formulas: Schedule!B2, Schedule!C2, Schedule!D2, Schedule!E2, Schedule!F2 +| zavora | failed | 0/133 | Schedule!B10: expected 0.0, actual None
Schedule!B11: expected -308872.0, actual None
Schedule!B2: expected 100000.0, actual None
Schedule!B3: expected 38000.0, actual None
Schedule!B4: expected 62000.0, actual None
Schedule!B5: expected 12000.0, actual None
Schedule!B6: expected 488.0, actual None
Schedule!B7: expected 719.0, actual None
Schedule!B8: expected 400872.0, actual None
Schedule!B9: expected -300872.0, actual None | + +zavora: 133/133 formula values wrong or missing (first mismatch batch: 10 shown, 10 missing, 0 wrong) diff --git a/results-2026-09-08/calc/aspose_cells_foss/financial_model.xlsx b/results-2026-09-08/calc/aspose_cells_foss/financial_model.xlsx new file mode 100644 index 0000000..e178725 Binary files /dev/null and b/results-2026-09-08/calc/aspose_cells_foss/financial_model.xlsx differ diff --git a/results-2026-09-08/calc/libreoffice/financial_model.xlsx b/results-2026-09-08/calc/libreoffice/financial_model.xlsx new file mode 100644 index 0000000..572d2e2 Binary files /dev/null and b/results-2026-09-08/calc/libreoffice/financial_model.xlsx differ diff --git a/results-2026-09-08/calc/results.json b/results-2026-09-08/calc/results.json new file mode 100644 index 0000000..d3482d5 --- /dev/null +++ b/results-2026-09-08/calc/results.json @@ -0,0 +1,187 @@ +{ + "engines": { + "aspose_cells_foss": { + "matched": 25, + "mismatched_cells": [ + { + "actual": null, + "cell": "Schedule!B11", + "expected": -308872.0 + }, + { + "actual": null, + "cell": "Schedule!B2", + "expected": 100000.0 + }, + { + "actual": null, + "cell": "Schedule!B3", + "expected": 38000.0 + }, + { + "actual": null, + "cell": "Schedule!B4", + "expected": 62000.0 + }, + { + "actual": null, + "cell": "Schedule!B6", + "expected": 488.0 + }, + { + "actual": null, + "cell": "Schedule!B7", + "expected": 719.0 + }, + { + "actual": null, + "cell": "Schedule!B8", + "expected": 400872.0 + }, + { + "actual": null, + "cell": "Schedule!B9", + "expected": -300872.0 + }, + { + "actual": null, + "cell": "Schedule!C11", + "expected": -306442.0 + }, + { + "actual": null, + "cell": "Schedule!C2", + "expected": 104500.0 + } + ], + "reason": "FOSS FormulaEvaluator returned no value for 107 formulas: Schedule!B2, Schedule!C2, Schedule!D2, Schedule!E2, Schedule!F2", + "status": "failed", + "total": 133 + }, + "libreoffice": { + "matched": 133, + "mismatched_cells": [], + "reason": null, + "status": "passed", + "total": 133 + }, + "wolfxl": { + "matched": 55, + "mismatched_cells": [ + { + "actual": null, + "cell": "Schedule!B11", + "expected": -308872.0 + }, + { + "actual": null, + "cell": "Schedule!B2", + "expected": 100000.0 + }, + { + "actual": null, + "cell": "Schedule!B3", + "expected": 38000.0 + }, + { + "actual": null, + "cell": "Schedule!B4", + "expected": 62000.0 + }, + { + "actual": null, + "cell": "Schedule!B8", + "expected": 400872.0 + }, + { + "actual": null, + "cell": "Schedule!B9", + "expected": -300872.0 + }, + { + "actual": null, + "cell": "Schedule!C11", + "expected": -306442.0 + }, + { + "actual": null, + "cell": "Schedule!C2", + "expected": 104500.0 + }, + { + "actual": null, + "cell": "Schedule!C3", + "expected": 39710.0 + }, + { + "actual": null, + "cell": "Schedule!C4", + "expected": 64790.0 + } + ], + "reason": "78/133 formula values wrong or missing (first mismatch batch: 10 shown, 10 missing, 0 wrong)", + "status": "failed", + "total": 133 + }, + "zavora": { + "matched": 0, + "mismatched_cells": [ + { + "actual": null, + "cell": "Schedule!B10", + "expected": 0.0 + }, + { + "actual": null, + "cell": "Schedule!B11", + "expected": -308872.0 + }, + { + "actual": null, + "cell": "Schedule!B2", + "expected": 100000.0 + }, + { + "actual": null, + "cell": "Schedule!B3", + "expected": 38000.0 + }, + { + "actual": null, + "cell": "Schedule!B4", + "expected": 62000.0 + }, + { + "actual": null, + "cell": "Schedule!B5", + "expected": 12000.0 + }, + { + "actual": null, + "cell": "Schedule!B6", + "expected": 488.0 + }, + { + "actual": null, + "cell": "Schedule!B7", + "expected": 719.0 + }, + { + "actual": null, + "cell": "Schedule!B8", + "expected": 400872.0 + }, + { + "actual": null, + "cell": "Schedule!B9", + "expected": -300872.0 + } + ], + "reason": "133/133 formula values wrong or missing (first mismatch batch: 10 shown, 10 missing, 0 wrong)", + "status": "failed", + "total": 133 + } + }, + "fixture": "fixtures/calc/financial_model.xlsx", + "oracle": "libreoffice/LibreOffice 26.8.0.3 bce0998afefdbc355585ca324285661a2170ba77" +} diff --git a/results-2026-09-08/calc/wolfxl/financial_model.xlsx b/results-2026-09-08/calc/wolfxl/financial_model.xlsx new file mode 100644 index 0000000..17f0223 Binary files /dev/null and b/results-2026-09-08/calc/wolfxl/financial_model.xlsx differ diff --git a/results-2026-09-08/calc/zavora/financial_model.xlsx b/results-2026-09-08/calc/zavora/financial_model.xlsx new file mode 100644 index 0000000..9074d5b Binary files /dev/null and b/results-2026-09-08/calc/zavora/financial_model.xlsx differ diff --git a/results-2026-09-08/cross-language/CONTEXT.md b/results-2026-09-08/cross-language/CONTEXT.md new file mode 100644 index 0000000..452083c --- /dev/null +++ b/results-2026-09-08/cross-language/CONTEXT.md @@ -0,0 +1,20 @@ +# ExcelBench Cross-Language Context + +This snapshot is for ecosystem context, not Python migration decisions. + +Use this snapshot to answer: how does WolfXL compare to mature spreadsheet tooling outside Python? + +Included adapters: +- `zavora-xlsx` + +Artifacts: +- [README](./README.md) +- [results.json](./results.json) +- [matrix.csv](./matrix.csv) + +Interpretation guidance: +- Keep this separate from the Python hero table. +- Cite the artifact path and generation date. +- Treat write-only adapters as ecosystem context, not drop-in migration advice. + +> Do not compare this table directly against the Python-first hero table without naming the scope. This run exists to position WolfXL against non-Python spreadsheet tooling. diff --git a/results-2026-09-08/cross-language/FIDELITY_DELTAS.md b/results-2026-09-08/cross-language/FIDELITY_DELTAS.md new file mode 100644 index 0000000..a91d7e9 --- /dev/null +++ b/results-2026-09-08/cross-language/FIDELITY_DELTAS.md @@ -0,0 +1,3 @@ +# Fidelity Deltas + +Need at least two runs in history.jsonl. diff --git a/results-2026-09-08/cross-language/README.md b/results-2026-09-08/cross-language/README.md new file mode 100644 index 0000000..8ea1f07 --- /dev/null +++ b/results-2026-09-08/cross-language/README.md @@ -0,0 +1,451 @@ +# ExcelBench Results + +*Generated: 2026-09-08 05:37 UTC* +*Profile: xlsx* +*Excel Version: 16.105.3* +*Platform: Darwin-arm64* + +## Overview + +> Condensed view — shows the **best score** across read/write for each library. See [Full Results Matrix](#full-results-matrix) for the complete R/W breakdown. + +**Tier 0 — Basic Values** + +| Feature | zavora-xlsx | +|---------|:-:| +| Cell Values | 🔴 | +| Formulas | 🟢 | +| Sheets | 🟢 | + +**Tier 1 — Formatting** + +| Feature | zavora-xlsx | +|---------|:-:| +| Alignment | 🟠 | +| Bg Colors | 🟢 | +| Borders | 🔴 | +| Dimensions | 🟠 | +| Num Fmt | 🟢 | +| Text Fmt | 🟢 | + +**Tier 2 — Advanced** + +| Feature | zavora-xlsx | +|---------|:-:| +| chart_anchor | 🔴 | +| Comments | 🟢 | +| Cond Fmt | 🔴 | +| Validation | 🔴 | +| Freeze | 🔴 | +| Hyperlinks | 🔴 | +| Images | 🔴 | +| Merged | 🟢 | +| page_setup | 🔴 | +| sheet_protection | 🔴 | + +**Tier 3 — Workbook Metadata** + +| Feature | zavora-xlsx | +|---------|:-:| +| Named Ranges | 🟢 | +| Tables | 🟠 | + +## Library Tiers + +> Libraries ranked by their best capability (max of read/write green features). + +| Tier | Library | Caps | Modify | Green Features | Summary | +|:----:|---------|:----:|:------:|:--------------:|---------| +| **B** | zavora-xlsx | W | No | 8/21 | 8/21 features with full fidelity | + +## Score Legend + +| Score | Meaning | +|-------|---------| +| 🟢 3 | Complete — all basic and edge cases pass | +| 🟡 2 | Functional — all basic pass, one or more edge cases fail | +| 🟠 1 | Minimal — at least one basic case passes, but not all basic cases | +| 🔴 0 | Unsupported — errors or data loss | +| ➖ | Not applicable | + +## Full Results Matrix + +**Tier 0 — Basic Values** + +| Feature | zavora-xlsx (W) | +|---------|------------| +| [cell_values](#cell_values-details) | 🔴 0 | +| [formulas](#formulas-details) | 🟢 3 | +| [multiple_sheets](#multiple_sheets-details) | 🟢 3 | + +**Tier 1 — Formatting** + +| Feature | zavora-xlsx (W) | +|---------|------------| +| [alignment](#alignment-details) | 🟠 1 | +| [background_colors](#background_colors-details) | 🟢 3 | +| [borders](#borders-details) | 🔴 0 | +| [dimensions](#dimensions-details) | 🟠 1 | +| [number_formats](#number_formats-details) | 🟢 3 | +| [text_formatting](#text_formatting-details) | 🟢 3 | + +**Tier 2 — Advanced** + +| Feature | zavora-xlsx (W) | +|---------|------------| +| [chart_anchor](#chart_anchor-details) | 🔴 0 | +| [comments](#comments-details) | 🟢 3 | +| [conditional_formatting](#conditional_formatting-details) | 🔴 0 | +| [data_validation](#data_validation-details) | 🔴 0 | +| [freeze_panes](#freeze_panes-details) | 🔴 0 | +| [hyperlinks](#hyperlinks-details) | 🔴 0 | +| [images](#images-details) | 🔴 0 | +| [merged_cells](#merged_cells-details) | 🟢 3 | +| [page_setup](#page_setup-details) | 🔴 0 | +| [pivot_tables](#pivot_tables-details) | ➖ | +| [sheet_protection](#sheet_protection-details) | 🔴 0 | + +**Tier 3 — Workbook Metadata** + +| Feature | zavora-xlsx (W) | +|---------|------------| +| [named_ranges](#named_ranges-details) | 🟢 3 | +| [tables](#tables-details) | 🟠 1 | + +## Notes + +- **pivot_tables**: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +## Statistics + +| Library | Mode | Tests | Passed | Failed | Pass Rate | Green Features | +|---------|------|-------|--------|--------|-----------|----------------| +| zavora-xlsx | W | 133 | 63 | 70 | 47% | 8/21 | + +## Libraries Tested + +- **zavora-xlsx** v0.1.2 (rust) - write; modify: No + +## Diagnostics Summary + +| Group | Value | Count | +|-------|-------|-------| +| category | data_mismatch | 4 | +| category | unsupported_feature | 66 | +| severity | error | 4 | +| severity | warning | 66 | + +### Diagnostic Details + +| Feature | Library | Test Case | Operation | Category | Severity | Message | +|---------|---------|-----------|-----------|----------|----------|---------| +| cell_values | zavora-xlsx | string_simple | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | string_unicode | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | string_empty | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | string_long | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | string_newline | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | number_integer | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | number_float | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | number_negative | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | number_large | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | number_scientific | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | date_standard | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | datetime | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | boolean_true | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | boolean_false | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | error_div0 | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | error_na | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | error_value | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| cell_values | zavora-xlsx | blank | write | unsupported_feature | warning | RuntimeError: unsupported cell type "date" at cell_values!B12 | +| alignment | zavora-xlsx | v_top | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| borders | zavora-xlsx | thin_all | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | medium_all | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | thick_all | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | double | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | dashed | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | dotted | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | dash_dot | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | dash_dot_dot | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | top_only | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | bottom_only | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | left_only | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | right_only | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | diagonal_up | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | diagonal_down | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | diagonal_both | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | color_red | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | color_blue | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | color_custom | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | mixed_styles | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| borders | zavora-xlsx | mixed_colors | write | unsupported_feature | warning | RuntimeError: unsupported border style "dashDot" | +| dimensions | zavora-xlsx | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | zavora-xlsx | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| conditional_formatting | zavora-xlsx | cf_cell_gt | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| conditional_formatting | zavora-xlsx | cf_formula_cross_sheet | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| conditional_formatting | zavora-xlsx | cf_text_contains | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| conditional_formatting | zavora-xlsx | cf_data_bar | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| conditional_formatting | zavora-xlsx | cf_color_scale | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| conditional_formatting | zavora-xlsx | cf_stop_if_true | write | unsupported_feature | warning | RuntimeError: unsupported payload part: conditional_formats | +| data_validation | zavora-xlsx | dv_list_csv | write | unsupported_feature | warning | RuntimeError: unsupported payload part: validations | +| data_validation | zavora-xlsx | dv_list_range | write | unsupported_feature | warning | RuntimeError: unsupported payload part: validations | +| data_validation | zavora-xlsx | dv_cross_sheet | write | unsupported_feature | warning | RuntimeError: unsupported payload part: validations | +| data_validation | zavora-xlsx | dv_custom_formula | write | unsupported_feature | warning | RuntimeError: unsupported payload part: validations | +| data_validation | zavora-xlsx | dv_whole_between | write | unsupported_feature | warning | RuntimeError: unsupported payload part: validations | +| hyperlinks | zavora-xlsx | link_external | write | unsupported_feature | warning | RuntimeError: unsupported hyperlink part: tooltip | +| hyperlinks | zavora-xlsx | link_internal | write | unsupported_feature | warning | RuntimeError: unsupported hyperlink part: tooltip | +| hyperlinks | zavora-xlsx | link_mailto | write | unsupported_feature | warning | RuntimeError: unsupported hyperlink part: tooltip | +| hyperlinks | zavora-xlsx | link_long | write | unsupported_feature | warning | RuntimeError: unsupported hyperlink part: tooltip | +| images | zavora-xlsx | image_one_cell | write | unsupported_feature | warning | RuntimeError: unsupported payload part: pictures | +| images | zavora-xlsx | image_two_cell_offset | write | unsupported_feature | warning | RuntimeError: unsupported payload part: pictures | +| freeze_panes | zavora-xlsx | freeze_b2 | write | unsupported_feature | warning | RuntimeError: unsupported pane part: top_left_cell | +| freeze_panes | zavora-xlsx | freeze_d5 | write | unsupported_feature | warning | RuntimeError: unsupported pane part: top_left_cell | +| freeze_panes | zavora-xlsx | split_2x1 | write | unsupported_feature | warning | RuntimeError: unsupported pane part: top_left_cell | +| tables | zavora-xlsx | tbl_with_totals | write | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}} | +| sheet_protection | zavora-xlsx | prot_basic | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement sheet protection writes | +| sheet_protection | zavora-xlsx | prot_password | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement sheet protection writes | +| sheet_protection | zavora-xlsx | prot_granular | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement sheet protection writes | +| page_setup | zavora-xlsx | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement page setup writes | +| page_setup | zavora-xlsx | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement page setup writes | +| page_setup | zavora-xlsx | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement page setup writes | +| chart_anchor | zavora-xlsx | chart_bar | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement chart anchor writes | +| chart_anchor | zavora-xlsx | chart_line | write | unsupported_feature | warning | NotImplementedError: zavora-xlsx does not implement chart anchor writes | + +## Detailed Results + + +### alignment + +**zavora-xlsx** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Align - left | basic | ✅ | +| Align - center | basic | ✅ | +| Align - right | basic | ✅ | +| Align - top | basic | ❌ | +| Align - center | basic | ✅ | +| Align - bottom | basic | ✅ | +| Align - wrap text | basic | ✅ | +| Align - rotation 45 | basic | ✅ | +| Align - indent 2 | basic | ✅ | + + +### background_colors + +**zavora-xlsx** — Write: 🟢 3 + + +### borders + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Border - thin all edges | basic | ❌ | +| Border - medium all edges | basic | ❌ | +| Border - thick all edges | basic | ❌ | +| Border - double line | basic | ❌ | +| Border - dashed | basic | ❌ | +| Border - dotted | basic | ❌ | +| Border - dash-dot | basic | ❌ | +| Border - dash-dot-dot | basic | ❌ | +| Border - top only | basic | ❌ | +| Border - bottom only | basic | ❌ | +| Border - left only | basic | ❌ | +| Border - right only | basic | ❌ | +| Border - diagonal up | basic | ❌ | +| Border - diagonal down | basic | ❌ | +| Border - diagonal both | basic | ❌ | +| Border - red color | basic | ❌ | +| Border - blue color | basic | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | +| Border - mixed styles per edge | basic | ❌ | +| Border - mixed colors per edge | basic | ❌ | + + +### cell_values + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| String - simple | basic | ❌ | +| String - unicode | basic | ❌ | +| String - empty | basic | ❌ | +| String - long (1000 chars) | basic | ❌ | +| String - with newlines | basic | ❌ | +| Number - integer | basic | ❌ | +| Number - float | basic | ❌ | +| Number - negative | basic | ❌ | +| Number - large | basic | ❌ | +| Number - scientific notation | basic | ❌ | +| Date - standard | basic | ❌ | +| DateTime - with time | basic | ❌ | +| Boolean - TRUE | basic | ❌ | +| Boolean - FALSE | basic | ❌ | +| Error - #DIV/0! | basic | ❌ | +| Error - #N/A | basic | ❌ | +| Error - #VALUE! | basic | ❌ | +| Blank cell | basic | ❌ | + + +### chart_anchor + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + + +### comments + +**zavora-xlsx** — Write: 🟢 3 + + +### conditional_formatting + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | +| CF: text contains | edge | ❌ | +| CF: data bar | edge | ❌ | +| CF: 3-color scale | edge | ❌ | +| CF: stop-if-true priority | edge | ❌ | + + +### data_validation + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| DV: list from CSV | basic | ❌ | +| DV: list from range | edge | ❌ | +| DV: cross-sheet named range | edge | ❌ | +| DV: custom formula | edge | ❌ | +| DV: whole number with error | basic | ❌ | + + +### dimensions + +**zavora-xlsx** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ✅ | +| Column width - E = 8 | basic | ✅ | + + +### formulas + +**zavora-xlsx** — Write: 🟢 3 + + +### freeze_panes + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Freeze panes at B2 | basic | ❌ | +| Freeze panes at D5 | edge | ❌ | +| Split panes row=2 col=1 | edge | ❌ | + + +### hyperlinks + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + + +### images + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + + +### merged_cells + +**zavora-xlsx** — Write: 🟢 3 + + +### multiple_sheets + +**zavora-xlsx** — Write: 🟢 3 + + +### named_ranges + +**zavora-xlsx** — Write: 🟢 3 + + +### number_formats + +**zavora-xlsx** — Write: 🟢 3 + + +### page_setup + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + + +### pivot_tables + +**zavora-xlsx** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + + +### sheet_protection + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + + +### tables + +**zavora-xlsx** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Table: basic 3-col | basic | ✅ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ✅ | +| Table: single column | edge | ✅ | +| Table: header only (no data rows) | edge | ✅ | +| Table: with autoFilter | edge | ✅ | + + +### text_formatting + +**zavora-xlsx** — Write: 🟢 3 + +--- +*Benchmark version: 0.1.0* \ No newline at end of file diff --git a/results-2026-09-08/cross-language/WHY_FAILED.md b/results-2026-09-08/cross-language/WHY_FAILED.md new file mode 100644 index 0000000..4476130 --- /dev/null +++ b/results-2026-09-08/cross-language/WHY_FAILED.md @@ -0,0 +1,421 @@ +# Why Failed + +## cell_values / zavora-xlsx / write / string_simple + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / string_unicode + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / string_empty + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / string_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / string_newline + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / number_integer + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / number_float + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / number_negative + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / number_large + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / number_scientific + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / date_standard + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / datetime + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / boolean_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / boolean_false + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / error_div0 + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / error_na + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / error_value + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / zavora-xlsx / write / blank + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / zavora-xlsx / write / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / zavora-xlsx / write / thin_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / medium_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / thick_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / double + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / dashed + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / dotted + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / dash_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / dash_dot_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / top_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / bottom_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / left_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / right_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / diagonal_up + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / diagonal_down + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / diagonal_both + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / mixed_styles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / zavora-xlsx / write / mixed_colors + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / zavora-xlsx / write / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / zavora-xlsx / write / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / zavora-xlsx / write / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / zavora-xlsx / write / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / zavora-xlsx / write / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / zavora-xlsx / write / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / zavora-xlsx / write / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / zavora-xlsx / write / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / zavora-xlsx / write / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / zavora-xlsx / write / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / zavora-xlsx / write / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / zavora-xlsx / write / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / zavora-xlsx / write / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / zavora-xlsx / write / link_external + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / zavora-xlsx / write / link_internal + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / zavora-xlsx / write / link_mailto + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / zavora-xlsx / write / link_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / zavora-xlsx / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / zavora-xlsx / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / zavora-xlsx / write / freeze_b2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / zavora-xlsx / write / freeze_d5 + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / zavora-xlsx / write / split_2x1 + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / zavora-xlsx / write / tbl_with_totals + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## sheet_protection / zavora-xlsx / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / zavora-xlsx / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / zavora-xlsx / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / zavora-xlsx / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / zavora-xlsx / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / zavora-xlsx / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / zavora-xlsx / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / zavora-xlsx / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression diff --git a/results-2026-09-08/cross-language/history.jsonl b/results-2026-09-08/cross-language/history.jsonl new file mode 100644 index 0000000..c77275f --- /dev/null +++ b/results-2026-09-08/cross-language/history.jsonl @@ -0,0 +1 @@ +{"run_date": "2026-09-08T05:37:26.998622+00:00", "commit": "9a0b300", "profile": "xlsx", "scores": {"zavora-xlsx": {"cell_values": {"read": null, "write": 0}, "formulas": {"read": null, "write": 3}, "text_formatting": {"read": null, "write": 3}, "background_colors": {"read": null, "write": 3}, "number_formats": {"read": null, "write": 3}, "alignment": {"read": null, "write": 1}, "borders": {"read": null, "write": 0}, "dimensions": {"read": null, "write": 1}, "multiple_sheets": {"read": null, "write": 3}, "merged_cells": {"read": null, "write": 3}, "conditional_formatting": {"read": null, "write": 0}, "data_validation": {"read": null, "write": 0}, "hyperlinks": {"read": null, "write": 0}, "images": {"read": null, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": null, "write": 3}, "freeze_panes": {"read": null, "write": 0}, "named_ranges": {"read": null, "write": 3}, "tables": {"read": null, "write": 1}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}}} diff --git a/results-2026-09-08/cross-language/matrix.csv b/results-2026-09-08/cross-language/matrix.csv new file mode 100644 index 0000000..64eef0f --- /dev/null +++ b/results-2026-09-08/cross-language/matrix.csv @@ -0,0 +1,23 @@ +library,feature,read_score,write_score +zavora-xlsx,cell_values,,0 +zavora-xlsx,formulas,,3 +zavora-xlsx,text_formatting,,3 +zavora-xlsx,background_colors,,3 +zavora-xlsx,number_formats,,3 +zavora-xlsx,alignment,,1 +zavora-xlsx,borders,,0 +zavora-xlsx,dimensions,,1 +zavora-xlsx,multiple_sheets,,3 +zavora-xlsx,merged_cells,,3 +zavora-xlsx,conditional_formatting,,0 +zavora-xlsx,data_validation,,0 +zavora-xlsx,hyperlinks,,0 +zavora-xlsx,images,,0 +zavora-xlsx,pivot_tables,, +zavora-xlsx,comments,,3 +zavora-xlsx,freeze_panes,,0 +zavora-xlsx,named_ranges,,3 +zavora-xlsx,tables,,1 +zavora-xlsx,sheet_protection,,0 +zavora-xlsx,page_setup,,0 +zavora-xlsx,chart_anchor,,0 \ No newline at end of file diff --git a/results-2026-09-08/cross-language/results.json b/results-2026-09-08/cross-language/results.json new file mode 100644 index 0000000..5d31efd --- /dev/null +++ b/results-2026-09-08/cross-language/results.json @@ -0,0 +1,4326 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-09-08T05:37:26.998622+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx" + }, + "libraries": { + "zavora-xlsx": { + "name": "zavora-xlsx", + "version": "0.1.2", + "language": "rust", + "capabilities": [ + "write" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "string_simple": { + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_simple", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_unicode", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_empty", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_long", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_newline", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_integer", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_float", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "write": { + "passed": false, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_negative", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_large", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_scientific", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "write": { + "passed": false, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "date_standard", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "write": { + "passed": false, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "datetime", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_true", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_false", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_div0", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_na", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_value", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "unsupported cell type \"date\" at cell_values!B12" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "blank", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported cell type \"date\" at cell_values!B12", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bold": { + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Calibri", + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Calibri", + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Calibri", + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Calibri", + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bg_red": { + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "h_left": { + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "write": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "write": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "thin_all": { + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thin_all", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "medium_all", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thick_all", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "double", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dashed", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dotted", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "top_only", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "bottom_only", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "left_only", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "right_only", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "write": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_styles", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "error": "unsupported border style \"dashDot\"" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported border style \"dashDot\"", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "row_height_30": { + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "error": "unsupported payload part: conditional_formats" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: conditional_formats", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "error": "unsupported payload part: validations" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: validations", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "unsupported payload part: validations" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: validations", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "unsupported payload part: validations" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: validations", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "unsupported payload part: validations" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: validations", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "error": "unsupported payload part: validations" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: validations", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "link_external": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "error": "unsupported hyperlink part: tooltip" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported hyperlink part: tooltip", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "error": "unsupported hyperlink part: tooltip" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported hyperlink part: tooltip", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "error": "unsupported hyperlink part: tooltip" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported hyperlink part: tooltip", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "error": "unsupported hyperlink part: tooltip" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported hyperlink part: tooltip", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "unsupported payload part: pictures" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: pictures", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "unsupported payload part: pictures" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "RuntimeError: unsupported payload part: pictures", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "comments", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "comment_legacy": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "unsupported pane part: top_left_cell" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": null + }, + "adapter_message": "RuntimeError: unsupported pane part: top_left_cell", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "unsupported pane part: top_left_cell" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": null + }, + "adapter_message": "RuntimeError: unsupported pane part: top_left_cell", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "unsupported pane part: top_left_cell" + }, + "notes": "Write failed: RuntimeError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": null + }, + "adapter_message": "RuntimeError: unsupported pane part: top_left_cell", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "nr_simple_cell": { + "write": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "write": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "write": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "write": { + "passed": true, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "write": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "write": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "tbl_basic": { + "write": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": false, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 0 + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "write": { + "passed": true, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "write": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "write": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "write": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "zavora-xlsx does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "zavora-xlsx does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "zavora-xlsx does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "zavora-xlsx does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "zavora-xlsx does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "zavora-xlsx does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "zavora-xlsx", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "zavora-xlsx does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "zavora-xlsx does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: zavora-xlsx does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/results-2026-09-08/mutation/README.md b/results-2026-09-08/mutation/README.md new file mode 100644 index 0000000..e44a2e6 --- /dev/null +++ b/results-2026-09-08/mutation/README.md @@ -0,0 +1,19 @@ +# ExcelBench Mutation Results + +*Generated: 2026-09-08T06:28:04Z* +*Template SHA-256: da08cc9e607f267b438ec7ce2480d6eb3650d1c19928f283a18296a2b79d808e* +*Repeats: 3* + +## Comparison + +| Engine | Wall ms | Peak RSS KB | Preservation score | Lost parts | Verdict | +|--------|---------|-------------|--------------------|------------|---------| +| aspose-cells-foss | 690.000 | 170752.000 | 60.000 | 3 | Loss detected | +| openpyxl | 710.000 | 170336.000 | 60.000 | 3 | Loss detected | +| wolfxl | 710.000 | 175488.000 | 100.000 | 0 | Preserved | +| zavora-xlsx | 1270.000 | 169520.000 | 0.000 | 1 | Mutation integrity failed | + +## Notes + +Wall time and peak RSS are measured in isolated subprocesses with macOS `/usr/bin/time -l`. +Preservation compares each output package against the original template. It does not measure formula recalculation or rendering. diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-input.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-input.xlsx differ diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-output.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-output.xlsx new file mode 100644 index 0000000..d646557 Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-1-output.xlsx differ diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-input.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-input.xlsx differ diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-output.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-output.xlsx new file mode 100644 index 0000000..d646557 Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-2-output.xlsx differ diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-input.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-input.xlsx differ diff --git a/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-output.xlsx b/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-output.xlsx new file mode 100644 index 0000000..051b07b Binary files /dev/null and b/results-2026-09-08/mutation/aspose-cells-foss/repeat-3-output.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-1-input.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-1-input.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-1-output.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-1-output.xlsx new file mode 100644 index 0000000..e51abdc Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-1-output.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-2-input.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-2-input.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-2-output.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-2-output.xlsx new file mode 100644 index 0000000..c06437f Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-2-output.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-3-input.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-3-input.xlsx differ diff --git a/results-2026-09-08/mutation/openpyxl/repeat-3-output.xlsx b/results-2026-09-08/mutation/openpyxl/repeat-3-output.xlsx new file mode 100644 index 0000000..c06437f Binary files /dev/null and b/results-2026-09-08/mutation/openpyxl/repeat-3-output.xlsx differ diff --git a/results-2026-09-08/mutation/results.json b/results-2026-09-08/mutation/results.json new file mode 100644 index 0000000..4ab0745 --- /dev/null +++ b/results-2026-09-08/mutation/results.json @@ -0,0 +1,743 @@ +{ + "engines": { + "aspose-cells-foss": { + "available": true, + "details": { + "added_parts": [ + "xl/sharedStrings.xml" + ], + "customXml_identical": false, + "dangling_rels": [], + "element_diffs": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + } + ], + "lost_parts": [ + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml" + ], + "missing_content_types": [], + "mutations_landed": true + }, + "peak_rss_kb_median": 170752.0, + "preservation_score": 60.0, + "status": "passed", + "wall_ms_median": 690.0 + }, + "openpyxl": { + "available": true, + "details": { + "added_parts": [], + "customXml_identical": false, + "dangling_rels": [], + "element_diffs": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + } + ], + "lost_parts": [ + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml" + ], + "missing_content_types": [], + "mutations_landed": true + }, + "peak_rss_kb_median": 170336.0, + "preservation_score": 60.0, + "status": "passed", + "wall_ms_median": 710.0 + }, + "wolfxl": { + "available": true, + "details": { + "added_parts": [ + "xl/calcChain.xml" + ], + "customXml_identical": true, + "dangling_rels": [], + "element_diffs": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + } + ], + "lost_parts": [], + "missing_content_types": [], + "mutations_landed": true + }, + "peak_rss_kb_median": 175488.0, + "preservation_score": 100.0, + "status": "passed", + "wall_ms_median": 710.0 + }, + "zavora-xlsx": { + "available": true, + "details": { + "added_parts": [ + "xl/sharedStrings.xml" + ], + "customXml_identical": true, + "dangling_rels": [], + "element_diffs": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "pane", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "tableParts", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": false, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "pane", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": true + } + ], + "integrity_failure": "mutated cell values did not match requested values", + "lost_parts": [ + "xl/worksheets/_rels/sheet3.xml.rels" + ], + "missing_content_types": [], + "mutations_landed": false + }, + "peak_rss_kb_median": 169520.0, + "preservation_score": 0.0, + "status": "integrity-failed", + "wall_ms_median": 1270.0 + } + }, + "metadata": { + "platform": "Darwin", + "repeats": 3, + "template_sha256": "da08cc9e607f267b438ec7ce2480d6eb3650d1c19928f283a18296a2b79d808e", + "timestamp": "2026-09-08T06:28:04Z" + } +} diff --git a/results-2026-09-08/mutation/wolfxl/repeat-1-input.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-1-input.xlsx differ diff --git a/results-2026-09-08/mutation/wolfxl/repeat-1-output.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-1-output.xlsx new file mode 100644 index 0000000..bb25a81 Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-1-output.xlsx differ diff --git a/results-2026-09-08/mutation/wolfxl/repeat-2-input.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-2-input.xlsx differ diff --git a/results-2026-09-08/mutation/wolfxl/repeat-2-output.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-2-output.xlsx new file mode 100644 index 0000000..bb25a81 Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-2-output.xlsx differ diff --git a/results-2026-09-08/mutation/wolfxl/repeat-3-input.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-3-input.xlsx differ diff --git a/results-2026-09-08/mutation/wolfxl/repeat-3-output.xlsx b/results-2026-09-08/mutation/wolfxl/repeat-3-output.xlsx new file mode 100644 index 0000000..c85af3c Binary files /dev/null and b/results-2026-09-08/mutation/wolfxl/repeat-3-output.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-1-input.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-1-input.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-1-output.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-1-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-1-output.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-2-input.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-2-input.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-2-output.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-2-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-2-output.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-3-input.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-3-input.xlsx differ diff --git a/results-2026-09-08/mutation/zavora-xlsx/repeat-3-output.xlsx b/results-2026-09-08/mutation/zavora-xlsx/repeat-3-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-09-08/mutation/zavora-xlsx/repeat-3-output.xlsx differ diff --git a/results-2026-09-08/xlsx/FIDELITY_DELTAS.md b/results-2026-09-08/xlsx/FIDELITY_DELTAS.md new file mode 100644 index 0000000..a91d7e9 --- /dev/null +++ b/results-2026-09-08/xlsx/FIDELITY_DELTAS.md @@ -0,0 +1,3 @@ +# Fidelity Deltas + +Need at least two runs in history.jsonl. diff --git a/results-2026-09-08/xlsx/README.md b/results-2026-09-08/xlsx/README.md new file mode 100644 index 0000000..8bcc4d8 --- /dev/null +++ b/results-2026-09-08/xlsx/README.md @@ -0,0 +1,4025 @@ +# ExcelBench Results + +*Generated: 2026-09-08 05:35 UTC* +*Profile: xlsx* +*Excel Version: 16.105.3* +*Platform: Darwin-arm64* + +## Overview + +> Condensed view — shows the **best score** across read/write for each library. See [Full Results Matrix](#full-results-matrix) for the complete R/W breakdown. + +**Tier 0 — Basic Values** + +| Feature | aspose-cells-foss | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| Cell Values | 🟢 | 🟢 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | +| Formulas | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🟢 | 🟢 | 🔴 | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | +| Sheets | 🟢 | 🟢 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | + +**Tier 1 — Formatting** + +| Feature | aspose-cells-foss | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| Alignment | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟠 | 🟠 | 🟢 | +| Bg Colors | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | +| Borders | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | +| Dimensions | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟠 | 🟠 | +| Num Fmt | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟢 | +| Text Fmt | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | + +**Tier 2 — Advanced** + +| Feature | aspose-cells-foss | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| chart_anchor | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | +| Comments | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🔴 | 🔴 | +| Cond Fmt | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🔴 | +| Validation | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🔴 | +| Freeze | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🔴 | +| Hyperlinks | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🔴 | +| Images | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🔴 | 🔴 | +| Merged | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🔴 | +| page_setup | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | +| sheet_protection | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | + +**Tier 3 — Workbook Metadata** + +| Feature | aspose-cells-foss | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| Named Ranges | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | +| Tables | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🔴 | 🔴 | + +## Library Tiers + +> Libraries ranked by their best capability (max of read/write green features). + +| Tier | Library | Caps | Modify | Green Features | Summary | +|:----:|---------|:----:|:------:|:--------------:|---------| +| **S** | openpyxl | R+W | Rewrite | 21/21 | Reference adapter — full read + write fidelity | +| **S-** | wolfxl | R+W | Patch | 20/21 | Hybrid Rust+Python — near-full fidelity at 3-9x throughput | +| **A** | xlsxwriter | W | No | 15/21 | Best write-only option — full formatting support | +| **B** | aspose-cells-foss | R+W | Rewrite | 14/21 | 14/21 features with full fidelity | +| **B** | xlsxwriter-constmem | W | No | 12/21 | Memory-optimized write — loses images, comments, row height | +| **B** | xlwt | W | No | 4/21 | Legacy .xls writer — basic formatting subset | +| **C** | openpyxl-readonly | R | No | 3/21 | Streaming read — loses all formatting metadata | +| **C** | pandas | R+W | Rebuild | 3/21 | DataFrame abstraction — errors coerced to NaN on read | +| **C** | tablib | R+W | Rebuild | 3/21 | Dataset wrapper — matches pyexcel on fidelity | +| **C** | pyexcel | R+W | Rebuild | 2/21 | Meta-library wrapping openpyxl — preserves error values | +| **C** | pylightxl | R+W | Rebuild | 2/21 | Lightweight — basic values, no formatting API | +| **C** | python-calamine | R | No | 1/21 | Fast Rust-backed reader — cell values + sheet names only | +| **D** | polars | R | No | 0/21 | Rust DataFrame reader — columnar type coercion drops fidelity | + +## Score Legend + +| Score | Meaning | +|-------|---------| +| 🟢 3 | Complete — all basic and edge cases pass | +| 🟡 2 | Functional — all basic pass, one or more edge cases fail | +| 🟠 1 | Minimal — at least one basic case passes, but not all basic cases | +| 🔴 0 | Unsupported — errors or data loss | +| ➖ | Not applicable | + +## Full Results Matrix + +**Tier 0 — Basic Values** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | openpyxl (R) | openpyxl (W) | openpyxl-readonly (R) | pandas (R) | pandas (W) | polars (R) | pyexcel (R) | pyexcel (W) | pylightxl (R) | pylightxl (W) | python-calamine (R) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [cell_values](#cell_values-details) | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟠 1 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | +| [formulas](#formulas-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [multiple_sheets](#multiple_sheets-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | + +**Tier 1 — Formatting** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | openpyxl (R) | openpyxl (W) | openpyxl-readonly (R) | pandas (R) | pandas (W) | polars (R) | pyexcel (R) | pyexcel (W) | pylightxl (R) | pylightxl (W) | python-calamine (R) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [alignment](#alignment-details) | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟠 1 | 🟠 1 | 🟢 3 | +| [background_colors](#background_colors-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟠 1 | +| [borders](#borders-details) | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟠 1 | +| [dimensions](#dimensions-details) | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟠 1 | 🟠 1 | +| [number_formats](#number_formats-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | +| [text_formatting](#text_formatting-details) | 🟠 1 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟠 1 | + +**Tier 2 — Advanced** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | openpyxl (R) | openpyxl (W) | openpyxl-readonly (R) | pandas (R) | pandas (W) | polars (R) | pyexcel (R) | pyexcel (W) | pylightxl (R) | pylightxl (W) | python-calamine (R) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [chart_anchor](#chart_anchor-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | +| [comments](#comments-details) | 🟢 3 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🔴 0 | 🔴 0 | +| [conditional_formatting](#conditional_formatting-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [data_validation](#data_validation-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [freeze_panes](#freeze_panes-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [hyperlinks](#hyperlinks-details) | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [images](#images-details) | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🔴 0 | 🔴 0 | +| [merged_cells](#merged_cells-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [page_setup](#page_setup-details) | 🟠 1 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟡 2 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | +| [pivot_tables](#pivot_tables-details) | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ | +| [sheet_protection](#sheet_protection-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | + +**Tier 3 — Workbook Metadata** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | openpyxl (R) | openpyxl (W) | openpyxl-readonly (R) | pandas (R) | pandas (W) | polars (R) | pyexcel (R) | pyexcel (W) | pylightxl (R) | pylightxl (W) | python-calamine (R) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [named_ranges](#named_ranges-details) | 🟡 2 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟡 2 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | +| [tables](#tables-details) | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | + +## Notes + +- **alignment**: Known limitation: pylightxl alignment write is a no-op because the library does not support formatting writes. +- **cell_values**: Known limitation: pylightxl cell-values write has date/boolean/error fidelity limits due to writer encoding behavior. +- **alignment**: Known limitation: python-calamine alignment read is limited because its API does not expose style/alignment metadata. +- **cell_values**: Known limitation: python-calamine can surface formula error cells as blank values in current API responses. +- **cell_values, formulas, ... (22 features)**: Not applicable: xlrd does not support .xlsx input +- **pivot_tables**: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +## Statistics + +| Library | Mode | Tests | Passed | Failed | Pass Rate | Green Features | +|---------|------|-------|--------|--------|-----------|----------------| +| aspose-cells-foss | R | 133 | 113 | 20 | 85% | 11/21 | +| aspose-cells-foss | W | 133 | 101 | 32 | 76% | 14/21 | +| openpyxl | R | 133 | 133 | 0 | 100% | 21/21 | +| openpyxl | W | 133 | 133 | 0 | 100% | 21/21 | +| openpyxl-readonly | R | 133 | 26 | 107 | 20% | 3/21 | +| pandas | R | 133 | 19 | 114 | 14% | 1/21 | +| pandas | W | 133 | 26 | 107 | 20% | 3/21 | +| polars | R | 133 | 17 | 116 | 13% | 0/21 | +| pyexcel | R | 133 | 22 | 111 | 17% | 2/21 | +| pyexcel | W | 133 | 8 | 125 | 6% | 2/21 | +| pylightxl | R | 133 | 22 | 111 | 17% | 2/21 | +| pylightxl | W | 133 | 8 | 125 | 6% | 2/21 | +| python-calamine | R | 133 | 19 | 114 | 14% | 1/21 | +| tablib | R | 133 | 22 | 111 | 17% | 2/21 | +| tablib | W | 133 | 26 | 107 | 20% | 3/21 | +| wolfxl | R | 133 | 129 | 4 | 97% | 20/21 | +| wolfxl | W | 133 | 131 | 2 | 98% | 19/21 | +| xlsxwriter | W | 133 | 112 | 21 | 84% | 15/21 | +| xlsxwriter-constmem | W | 133 | 105 | 28 | 79% | 12/21 | +| xlwt | W | 133 | 72 | 61 | 54% | 4/21 | + +## Libraries Tested + +- **aspose-cells-foss** v26.7.0 (python) - read, write; modify: Rewrite +- **openpyxl** v3.1.5 (python) - read, write; modify: Rewrite +- **openpyxl-readonly** v3.1.5 (python) - read; modify: No +- **pandas** v3.0.0 (python) - read, write; modify: Rebuild +- **polars** v1.38.1 (python) - read; modify: No +- **pyexcel** v0.7.4 (python) - read, write; modify: Rebuild +- **pylightxl** v1.61 (python) - read, write; modify: Rebuild +- **python-calamine** v0.6.1 (python) - read; modify: No +- **tablib** v3.9.0 (python) - read, write; modify: Rebuild +- **wolfxl** v2.1.0 (python) - modify, read, write; modify: Patch +- **xlrd** v2.0.2 (python) - read; modify: No +- **xlsxwriter** v3.2.9 (python) - write; modify: No +- **xlsxwriter-constmem** v3.2.9 (python) - write; modify: No +- **xlwt** v1.3.0 (python) - write; modify: No + +## Diagnostics Summary + +| Group | Value | Count | +|-------|-------|-------| +| category | data_mismatch | 801 | +| category | internal | 31 | +| category | invalid_input | 69 | +| category | unsupported_feature | 515 | +| severity | error | 901 | +| severity | warning | 515 | + +### Diagnostic Details + +| Feature | Library | Test Case | Operation | Category | Severity | Message | +|---------|---------|-----------|-----------|----------|----------|---------| +| cell_values | python-calamine | error_div0 | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'} | +| cell_values | python-calamine | error_na | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'} | +| cell_values | python-calamine | error_value | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'} | +| cell_values | aspose-cells-foss | date_standard | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'date', 'value': '2026-02-04'}, actual={'type': 'number', 'value': 46057} | +| cell_values | aspose-cells-foss | datetime | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'datetime', 'value': '2026-02-04T10:30:45'}, actual={'type': 'number', 'value': 46057.43802083333} | +| cell_values | pylightxl | string_simple | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | string_unicode | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | string_empty | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | string_long | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | string_newline | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | number_integer | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | number_float | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | number_negative | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | number_large | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | number_scientific | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | date_standard | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | datetime | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | boolean_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | boolean_false | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | error_div0 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | error_na | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | error_value | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pylightxl | blank | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| cell_values | pyexcel | string_simple | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | string_unicode | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | string_empty | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | string_long | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | string_newline | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | number_integer | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | number_float | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | number_negative | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | number_large | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | number_scientific | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | date_standard | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | datetime | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | boolean_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | boolean_false | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | error_div0 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | error_na | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | error_value | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pyexcel | blank | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| cell_values | pandas | error_div0 | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'} | +| cell_values | pandas | error_na | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'} | +| cell_values | pandas | error_value | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'} | +| cell_values | polars | error_div0 | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'} | +| cell_values | polars | error_na | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'} | +| cell_values | polars | error_value | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'} | +| formulas | python-calamine | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | python-calamine | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got blank | +| formulas | python-calamine | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | python-calamine | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | pylightxl | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | pylightxl | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| formulas | pylightxl | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | pylightxl | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | pyexcel | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | pyexcel | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| formulas | pyexcel | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | pyexcel | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | xlwt | formula_sum | write | internal | error | RuntimeError: Expected formula, got string | +| formulas | xlwt | formula_cell_ref | write | internal | error | RuntimeError: Expected formula, got string | +| formulas | xlwt | formula_concat | write | internal | error | RuntimeError: Expected formula, got string | +| formulas | xlwt | formula_cross_sheet | write | internal | error | RuntimeError: Expected formula, got string | +| formulas | pandas | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | pandas | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got blank | +| formulas | pandas | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | pandas | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | polars | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | polars | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got blank | +| formulas | polars | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | polars | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | tablib | formula_sum | read | internal | error | RuntimeError: Expected formula, got number | +| formulas | tablib | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| formulas | tablib | formula_concat | read | internal | error | RuntimeError: Expected formula, got string | +| formulas | tablib | formula_cross_sheet | read | internal | error | RuntimeError: Expected formula, got number | +| text_formatting | python-calamine | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | python-calamine | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | python-calamine | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | python-calamine | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | python-calamine | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | python-calamine | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | python-calamine | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | python-calamine | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | python-calamine | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | python-calamine | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | python-calamine | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | python-calamine | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | python-calamine | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | python-calamine | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | python-calamine | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | python-calamine | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | python-calamine | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | python-calamine | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | aspose-cells-foss | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={'underline': 'single', 'font_name': 'Aptos Narrow', 'font_size': 12.0, 'font_color': '#000000'} | +| text_formatting | aspose-cells-foss | bold | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | underline_single | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | underline_double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | strikethrough | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | bold_italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_size_8 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_size_14 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_size_24 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_size_36 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_arial | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_times | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | font_courier | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | color_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | aspose-cells-foss | combined | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants. | +| text_formatting | pylightxl | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | pylightxl | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | pylightxl | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | pylightxl | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | pylightxl | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | pylightxl | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | pylightxl | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | pylightxl | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | pylightxl | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | pylightxl | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | pylightxl | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | pylightxl | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | pylightxl | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | pylightxl | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | pylightxl | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | pylightxl | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | pylightxl | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | pylightxl | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | pylightxl | bold | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | underline_single | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | underline_double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | strikethrough | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | bold_italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_size_8 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_size_14 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_size_24 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_size_36 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_arial | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_times | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | font_courier | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | color_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | combined | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pyexcel | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | pyexcel | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | pyexcel | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | pyexcel | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | pyexcel | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | pyexcel | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | pyexcel | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | pyexcel | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | pyexcel | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | pyexcel | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | pyexcel | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | pyexcel | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | pyexcel | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | pyexcel | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | pyexcel | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | pyexcel | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | pyexcel | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | pyexcel | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | pyexcel | bold | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | underline_single | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | underline_double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | strikethrough | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | bold_italic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_size_8 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_size_14 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_size_24 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_size_36 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_arial | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_times | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | font_courier | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | color_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | combined | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | xlwt | color_green | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Arial', 'font_size': 10.0, 'font_color': '#008000'} | +| text_formatting | xlwt | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Arial', 'font_size': 10.0, 'font_color': '#993300'} | +| text_formatting | pandas | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | pandas | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | pandas | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | pandas | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | pandas | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | pandas | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | pandas | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | pandas | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | pandas | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | pandas | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | pandas | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | pandas | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | pandas | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | pandas | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | pandas | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | pandas | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | pandas | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | pandas | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | pandas | bold | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | italic | write | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | underline_single | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | underline_double | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | strikethrough | write | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | bold_italic | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_size_8 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_size_14 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_size_24 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_size_36 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_arial | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_times | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | font_courier | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | color_red | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | color_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | color_green | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | pandas | combined | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | openpyxl-readonly | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | openpyxl-readonly | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | openpyxl-readonly | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | openpyxl-readonly | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | openpyxl-readonly | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | openpyxl-readonly | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | openpyxl-readonly | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | openpyxl-readonly | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | openpyxl-readonly | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | openpyxl-readonly | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | openpyxl-readonly | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | openpyxl-readonly | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | openpyxl-readonly | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | openpyxl-readonly | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | openpyxl-readonly | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | openpyxl-readonly | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | openpyxl-readonly | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | openpyxl-readonly | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | polars | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | polars | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | polars | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | polars | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | polars | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | polars | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | polars | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | polars | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | polars | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | polars | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | polars | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | polars | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | polars | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | polars | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | polars | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | polars | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | polars | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | polars | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | tablib | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | tablib | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | tablib | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | tablib | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | tablib | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | tablib | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | tablib | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | tablib | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | tablib | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | tablib | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | tablib | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | tablib | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | tablib | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | tablib | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | tablib | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | tablib | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | tablib | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | tablib | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | tablib | bold | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | italic | write | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | underline_single | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | underline_double | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | strikethrough | write | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | bold_italic | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_size_8 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_size_14 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_size_24 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_size_36 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_arial | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_times | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | font_courier | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | color_red | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | color_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | color_green | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| text_formatting | tablib | combined | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0} | +| background_colors | python-calamine | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | python-calamine | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | python-calamine | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | python-calamine | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | pylightxl | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | pylightxl | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | pylightxl | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | pylightxl | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | pylightxl | bg_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| background_colors | pylightxl | bg_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| background_colors | pylightxl | bg_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| background_colors | pylightxl | bg_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| background_colors | pyexcel | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | pyexcel | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | pyexcel | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | pyexcel | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | pyexcel | bg_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| background_colors | pyexcel | bg_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| background_colors | pyexcel | bg_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| background_colors | pyexcel | bg_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| background_colors | xlwt | bg_green | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={'bg_color': '#008000'} | +| background_colors | xlwt | bg_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={'bg_color': '#993300'} | +| background_colors | pandas | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | pandas | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | pandas | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | pandas | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | pandas | bg_red | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | pandas | bg_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | pandas | bg_green | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | pandas | bg_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | openpyxl-readonly | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | openpyxl-readonly | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | openpyxl-readonly | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | openpyxl-readonly | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | polars | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | polars | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | polars | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | polars | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | tablib | bg_red | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | tablib | bg_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | tablib | bg_green | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | tablib | bg_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | tablib | bg_red | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | tablib | bg_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | tablib | bg_green | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | tablib | bg_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| number_formats | python-calamine | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | python-calamine | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | python-calamine | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | python-calamine | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | python-calamine | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | pylightxl | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | pylightxl | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | pylightxl | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | pylightxl | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | pylightxl | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | pylightxl | numfmt_currency | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| number_formats | pylightxl | numfmt_percent | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| number_formats | pylightxl | numfmt_date | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| number_formats | pylightxl | numfmt_scientific | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| number_formats | pylightxl | numfmt_custom_text | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| number_formats | pyexcel | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | pyexcel | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | pyexcel | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | pyexcel | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | pyexcel | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | pyexcel | numfmt_currency | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| number_formats | pyexcel | numfmt_percent | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| number_formats | pyexcel | numfmt_date | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| number_formats | pyexcel | numfmt_scientific | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| number_formats | pyexcel | numfmt_custom_text | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| number_formats | pandas | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | pandas | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | pandas | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | pandas | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | pandas | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | pandas | numfmt_currency | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={'number_format': 'General'} | +| number_formats | pandas | numfmt_percent | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={'number_format': 'General'} | +| number_formats | pandas | numfmt_date | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={'number_format': 'General'} | +| number_formats | pandas | numfmt_scientific | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={'number_format': 'General'} | +| number_formats | pandas | numfmt_custom_text | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={'number_format': 'General'} | +| number_formats | openpyxl-readonly | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | openpyxl-readonly | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | openpyxl-readonly | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | openpyxl-readonly | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | openpyxl-readonly | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | polars | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | polars | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | polars | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | polars | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | polars | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | tablib | numfmt_currency | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={} | +| number_formats | tablib | numfmt_percent | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| number_formats | tablib | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| number_formats | tablib | numfmt_scientific | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| number_formats | tablib | numfmt_custom_text | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| number_formats | tablib | numfmt_currency | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={'number_format': 'General'} | +| number_formats | tablib | numfmt_percent | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={'number_format': 'General'} | +| number_formats | tablib | numfmt_date | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={'number_format': 'General'} | +| number_formats | tablib | numfmt_scientific | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={'number_format': 'General'} | +| number_formats | tablib | numfmt_custom_text | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={'number_format': 'General'} | +| alignment | xlsxwriter | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | python-calamine | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | python-calamine | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | python-calamine | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | python-calamine | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | python-calamine | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | python-calamine | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | python-calamine | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | python-calamine | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | python-calamine | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | aspose-cells-foss | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | aspose-cells-foss | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | pylightxl | h_left | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | h_center | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | h_right | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | v_top | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | v_center | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | v_bottom | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | wrap_text | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | rotation_45 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | indent_2 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| alignment | pylightxl | h_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | h_center | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | h_right | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | v_top | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | v_center | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | v_bottom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | wrap_text | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | rotation_45 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | indent_2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pyexcel | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | pyexcel | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | pyexcel | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | pyexcel | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | pyexcel | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | pyexcel | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | pyexcel | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | pyexcel | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | pyexcel | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | pyexcel | h_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | h_center | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | h_right | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | v_top | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | v_center | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | v_bottom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | wrap_text | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | rotation_45 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | indent_2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pandas | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | pandas | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | pandas | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | pandas | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | pandas | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | pandas | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | pandas | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | pandas | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | pandas | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | pandas | h_left | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | pandas | h_center | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | pandas | h_right | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | pandas | v_top | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | pandas | v_center | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | pandas | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | pandas | wrap_text | write | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | pandas | rotation_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | pandas | indent_2 | write | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | xlsxwriter-constmem | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | openpyxl-readonly | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | openpyxl-readonly | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | openpyxl-readonly | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | openpyxl-readonly | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | openpyxl-readonly | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | openpyxl-readonly | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | openpyxl-readonly | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | openpyxl-readonly | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | openpyxl-readonly | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | polars | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | polars | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | polars | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | polars | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | polars | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | polars | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | polars | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | polars | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | polars | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | tablib | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | tablib | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | tablib | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | tablib | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | tablib | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | tablib | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | tablib | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | tablib | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | tablib | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | tablib | h_left | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | tablib | h_center | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | tablib | h_right | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | tablib | v_top | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | tablib | v_center | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | tablib | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | tablib | wrap_text | write | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | tablib | rotation_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | tablib | indent_2 | write | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| borders | python-calamine | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | python-calamine | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | python-calamine | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | python-calamine | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | python-calamine | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | python-calamine | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | python-calamine | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | python-calamine | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | python-calamine | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | python-calamine | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | python-calamine | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | python-calamine | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | python-calamine | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | aspose-cells-foss | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | aspose-cells-foss | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | aspose-cells-foss | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | aspose-cells-foss | diagonal_up | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | aspose-cells-foss | diagonal_down | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | aspose-cells-foss | diagonal_both | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | pylightxl | thin_all | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | medium_all | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | thick_all | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | double | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | dashed | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | dotted | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | dash_dot | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | dash_dot_dot | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | top_only | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | bottom_only | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | left_only | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | right_only | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | diagonal_up | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | diagonal_down | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | diagonal_both | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | color_red | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | color_blue | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | color_custom | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | mixed_styles | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | mixed_colors | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | thin_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | medium_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | thick_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dashed | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dotted | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dash_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dash_dot_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | top_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | bottom_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | left_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | right_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | diagonal_up | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | diagonal_down | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | diagonal_both | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | mixed_styles | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | mixed_colors | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pyexcel | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | pyexcel | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | pyexcel | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | pyexcel | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | pyexcel | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | pyexcel | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | pyexcel | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | pyexcel | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | pyexcel | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | pyexcel | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | pyexcel | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | pyexcel | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | pyexcel | thin_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | medium_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | thick_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dashed | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dotted | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dash_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dash_dot_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | top_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | bottom_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | left_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | right_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | diagonal_up | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | diagonal_down | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | diagonal_both | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | mixed_styles | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | mixed_colors | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | xlwt | diagonal_up | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={'border_diagonal_down': 'thin'} | +| borders | xlwt | diagonal_down | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={'border_diagonal_up': 'thin'} | +| borders | xlwt | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={'border_style': 'thin', 'border_color': '#993300'} | +| borders | xlwt | mixed_colors | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={'border_top_color': '#FF0000', 'border_bottom_color': '#008000', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00', 'border_style': 'thin'} | +| borders | pandas | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | pandas | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | pandas | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | pandas | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | pandas | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | pandas | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | pandas | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | pandas | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | pandas | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | pandas | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | pandas | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | pandas | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | pandas | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | pandas | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | pandas | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | pandas | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | pandas | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | pandas | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | pandas | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | pandas | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | pandas | thin_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | pandas | medium_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | pandas | thick_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | pandas | double | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | pandas | dashed | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | pandas | dotted | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | pandas | dash_dot | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | pandas | dash_dot_dot | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | pandas | top_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | pandas | bottom_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | pandas | left_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | pandas | right_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | pandas | diagonal_up | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | pandas | diagonal_down | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | pandas | diagonal_both | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | pandas | color_red | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | pandas | color_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | pandas | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | pandas | mixed_styles | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | pandas | mixed_colors | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | openpyxl-readonly | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | openpyxl-readonly | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | openpyxl-readonly | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | openpyxl-readonly | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | openpyxl-readonly | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | openpyxl-readonly | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | openpyxl-readonly | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | openpyxl-readonly | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | openpyxl-readonly | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | openpyxl-readonly | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | openpyxl-readonly | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | openpyxl-readonly | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | openpyxl-readonly | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | polars | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | polars | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | polars | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | polars | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | polars | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | polars | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | polars | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | polars | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | polars | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | polars | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | polars | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | polars | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | polars | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | polars | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | polars | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | polars | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | polars | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | polars | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | polars | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | polars | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | tablib | thin_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | tablib | medium_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | tablib | thick_all | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | tablib | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | tablib | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | tablib | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | tablib | dash_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | tablib | dash_dot_dot | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | tablib | top_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | tablib | bottom_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | tablib | left_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | tablib | right_only | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | tablib | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | tablib | diagonal_down | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | tablib | diagonal_both | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | tablib | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | tablib | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | tablib | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | tablib | mixed_styles | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | tablib | mixed_colors | read | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| borders | tablib | thin_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={} | +| borders | tablib | medium_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={} | +| borders | tablib | thick_all | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={} | +| borders | tablib | double | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | tablib | dashed | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | tablib | dotted | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | tablib | dash_dot | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={} | +| borders | tablib | dash_dot_dot | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={} | +| borders | tablib | top_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={} | +| borders | tablib | bottom_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={} | +| borders | tablib | left_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={} | +| borders | tablib | right_only | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={} | +| borders | tablib | diagonal_up | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| borders | tablib | diagonal_down | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| borders | tablib | diagonal_both | write | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| borders | tablib | color_red | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| borders | tablib | color_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| borders | tablib | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| borders | tablib | mixed_styles | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={} | +| borders | tablib | mixed_colors | write | data_mismatch | error | Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={} | +| dimensions | python-calamine | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | python-calamine | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | python-calamine | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | python-calamine | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | aspose-cells-foss | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 20.83203125} | +| dimensions | aspose-cells-foss | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 8.83203125} | +| dimensions | pylightxl | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | pylightxl | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | pylightxl | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | pylightxl | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | pylightxl | row_height_30 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature | +| dimensions | pylightxl | row_height_45 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature | +| dimensions | pylightxl | col_width_20 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature | +| dimensions | pylightxl | col_width_8 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature | +| dimensions | pyexcel | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | pyexcel | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | pyexcel | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | pyexcel | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | pyexcel | row_height_30 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing | +| dimensions | pyexcel | row_height_45 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing | +| dimensions | pyexcel | col_width_20 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing | +| dimensions | pyexcel | col_width_8 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing | +| dimensions | xlwt | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | xlwt | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | pandas | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | pandas | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | pandas | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | pandas | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | pandas | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | pandas | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | pandas | col_width_20 | write | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 13.0} | +| dimensions | pandas | col_width_8 | write | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 13.0} | +| dimensions | xlsxwriter-constmem | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | xlsxwriter-constmem | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | openpyxl-readonly | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | openpyxl-readonly | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | openpyxl-readonly | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | openpyxl-readonly | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | polars | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | polars | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | polars | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | polars | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | tablib | row_height_30 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | tablib | row_height_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | tablib | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| dimensions | tablib | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| dimensions | tablib | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | tablib | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | tablib | col_width_20 | write | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 13.0} | +| dimensions | tablib | col_width_8 | write | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 13.0} | +| multiple_sheets | polars | value_beta | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'string', 'value': 'Beta'}, actual={'type': 'blank'} | +| multiple_sheets | polars | value_gamma | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'string', 'value': 'Gamma'}, actual={'type': 'blank'} | +| merged_cells | python-calamine | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | python-calamine | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | python-calamine | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | python-calamine | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | pylightxl | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | pylightxl | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | pylightxl | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | pylightxl | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | pylightxl | merge_horizontal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature | +| merged_cells | pylightxl | merge_vertical | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature | +| merged_cells | pylightxl | merge_value_off_top_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature | +| merged_cells | pylightxl | merge_top_left_fill | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature | +| merged_cells | pyexcel | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | pyexcel | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | pyexcel | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | pyexcel | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | pyexcel | merge_horizontal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature | +| merged_cells | pyexcel | merge_vertical | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature | +| merged_cells | pyexcel | merge_value_off_top_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature | +| merged_cells | pyexcel | merge_top_left_fill | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature | +| merged_cells | xlwt | merge_horizontal | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': 'B2:D2', 'top_left_value': None} | +| merged_cells | xlwt | merge_vertical | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': 'B3:B5', 'top_left_value': None} | +| merged_cells | xlwt | merge_value_off_top_left | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': 'B6:D6', 'top_left_value': None, 'non_top_left_nonempty': 0} | +| merged_cells | xlwt | merge_top_left_fill | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': 'B7:D7', 'top_left_value': None, 'top_left_bg_color': None} | +| merged_cells | pandas | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | pandas | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | pandas | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | pandas | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | pandas | merge_horizontal | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | pandas | merge_vertical | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | pandas | merge_value_off_top_left | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | pandas | merge_top_left_fill | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | openpyxl-readonly | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | openpyxl-readonly | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | openpyxl-readonly | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | openpyxl-readonly | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | polars | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | polars | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | polars | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | polars | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_horizontal | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_vertical | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_value_off_top_left | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | tablib | merge_top_left_fill | read | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_horizontal | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_vertical | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None} | +| merged_cells | tablib | merge_value_off_top_left | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None} | +| merged_cells | tablib | merge_top_left_fill | write | data_mismatch | error | Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None} | +| conditional_formatting | python-calamine | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | python-calamine | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | python-calamine | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | python-calamine | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | python-calamine | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | python-calamine | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | wolfxl | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'format': {}}} | +| conditional_formatting | wolfxl | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'format': {}}} | +| conditional_formatting | wolfxl | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'format': {}}} | +| conditional_formatting | wolfxl | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': True, 'format': {}}} | +| conditional_formatting | pylightxl | cf_cell_gt | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_formula_cross_sheet | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_text_contains | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_data_bar | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_color_scale | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_stop_if_true | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| conditional_formatting | pylightxl | cf_cell_gt | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pylightxl | cf_formula_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pylightxl | cf_text_contains | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pylightxl | cf_data_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pylightxl | cf_color_scale | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pylightxl | cf_stop_if_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature | +| conditional_formatting | pyexcel | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pyexcel | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | pyexcel | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pyexcel | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | pyexcel | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | pyexcel | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | pyexcel | cf_cell_gt | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | pyexcel | cf_formula_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | pyexcel | cf_text_contains | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | pyexcel | cf_data_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | pyexcel | cf_color_scale | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | pyexcel | cf_stop_if_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature | +| conditional_formatting | xlwt | cf_cell_gt | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | xlwt | cf_formula_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | xlwt | cf_text_contains | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | xlwt | cf_data_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | xlwt | cf_color_scale | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | xlwt | cf_stop_if_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting | +| conditional_formatting | pandas | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pandas | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | pandas | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pandas | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | pandas | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | pandas | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | pandas | cf_cell_gt | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pandas | cf_formula_cross_sheet | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | pandas | cf_text_contains | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | pandas | cf_data_bar | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | pandas | cf_color_scale | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | pandas | cf_stop_if_true | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | openpyxl-readonly | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | polars | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | polars | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | polars | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | polars | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | polars | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | polars | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | tablib | cf_cell_gt | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | tablib | cf_formula_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | tablib | cf_text_contains | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | tablib | cf_data_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | tablib | cf_color_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | tablib | cf_stop_if_true | read | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| conditional_formatting | tablib | cf_cell_gt | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | tablib | cf_formula_cross_sheet | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={} | +| conditional_formatting | tablib | cf_text_contains | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={} | +| conditional_formatting | tablib | cf_data_bar | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={} | +| conditional_formatting | tablib | cf_color_scale | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={} | +| conditional_formatting | tablib | cf_stop_if_true | write | data_mismatch | error | Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={} | +| data_validation | python-calamine | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | python-calamine | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | python-calamine | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | python-calamine | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | python-calamine | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | pylightxl | dv_list_csv | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| data_validation | pylightxl | dv_list_range | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| data_validation | pylightxl | dv_cross_sheet | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| data_validation | pylightxl | dv_custom_formula | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| data_validation | pylightxl | dv_whole_between | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| data_validation | pylightxl | dv_list_csv | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature | +| data_validation | pylightxl | dv_list_range | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature | +| data_validation | pylightxl | dv_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature | +| data_validation | pylightxl | dv_custom_formula | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature | +| data_validation | pylightxl | dv_whole_between | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature | +| data_validation | pyexcel | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | pyexcel | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | pyexcel | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | pyexcel | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | pyexcel | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | pyexcel | dv_list_csv | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature | +| data_validation | pyexcel | dv_list_range | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature | +| data_validation | pyexcel | dv_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature | +| data_validation | pyexcel | dv_custom_formula | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature | +| data_validation | pyexcel | dv_whole_between | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature | +| data_validation | xlwt | dv_list_csv | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations | +| data_validation | xlwt | dv_list_range | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations | +| data_validation | xlwt | dv_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations | +| data_validation | xlwt | dv_custom_formula | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations | +| data_validation | xlwt | dv_whole_between | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations | +| data_validation | pandas | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | pandas | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | pandas | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | pandas | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | pandas | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | pandas | dv_list_csv | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | pandas | dv_list_range | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | pandas | dv_cross_sheet | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | pandas | dv_custom_formula | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | pandas | dv_whole_between | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | openpyxl-readonly | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | openpyxl-readonly | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | openpyxl-readonly | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | openpyxl-readonly | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | openpyxl-readonly | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | polars | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | polars | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | polars | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | polars | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | polars | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | tablib | dv_list_csv | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | tablib | dv_list_range | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | tablib | dv_cross_sheet | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | tablib | dv_custom_formula | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | tablib | dv_whole_between | read | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| data_validation | tablib | dv_list_csv | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '"Red,Green,Blue"', 'allow_blank': True}}, actual={} | +| data_validation | tablib | dv_list_range | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={} | +| data_validation | tablib | dv_cross_sheet | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={} | +| data_validation | tablib | dv_custom_formula | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={} | +| data_validation | tablib | dv_whole_between | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={} | +| hyperlinks | python-calamine | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | python-calamine | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | python-calamine | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | python-calamine | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | aspose-cells-foss | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': None, 'tooltip': 'Go to docs', 'internal': False}} | +| hyperlinks | aspose-cells-foss | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': None, 'tooltip': 'Jump to target', 'internal': True}} | +| hyperlinks | aspose-cells-foss | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': None, 'tooltip': 'Send email', 'internal': False}} | +| hyperlinks | aspose-cells-foss | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': None, 'tooltip': 'Encoded URL', 'internal': False}} | +| hyperlinks | pylightxl | link_external | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| hyperlinks | pylightxl | link_internal | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| hyperlinks | pylightxl | link_mailto | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| hyperlinks | pylightxl | link_long | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| hyperlinks | pylightxl | link_external | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature | +| hyperlinks | pylightxl | link_internal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature | +| hyperlinks | pylightxl | link_mailto | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature | +| hyperlinks | pylightxl | link_long | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature | +| hyperlinks | pyexcel | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | pyexcel | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | pyexcel | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | pyexcel | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | pyexcel | link_external | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| hyperlinks | pyexcel | link_internal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| hyperlinks | pyexcel | link_mailto | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| hyperlinks | pyexcel | link_long | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| hyperlinks | xlwt | link_external | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter | +| hyperlinks | xlwt | link_internal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter | +| hyperlinks | xlwt | link_mailto | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter | +| hyperlinks | xlwt | link_long | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter | +| hyperlinks | pandas | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | pandas | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | pandas | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | pandas | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | pandas | link_external | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | pandas | link_internal | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | pandas | link_mailto | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | pandas | link_long | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | openpyxl-readonly | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | openpyxl-readonly | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | openpyxl-readonly | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | openpyxl-readonly | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | polars | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | polars | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | polars | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | polars | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_external | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_internal | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | tablib | link_mailto | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_long | read | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_external | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_internal | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={} | +| hyperlinks | tablib | link_mailto | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={} | +| hyperlinks | tablib | link_long | write | data_mismatch | error | Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={} | +| images | python-calamine | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | python-calamine | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | aspose-cells-foss | image_one_cell | read | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind. | +| images | aspose-cells-foss | image_two_cell_offset | read | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind. | +| images | aspose-cells-foss | image_one_cell | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors. | +| images | aspose-cells-foss | image_two_cell_offset | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors. | +| images | pylightxl | image_one_cell | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| images | pylightxl | image_two_cell_offset | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| images | pylightxl | image_one_cell | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature | +| images | pylightxl | image_two_cell_offset | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature | +| images | pyexcel | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | pyexcel | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | pyexcel | image_one_cell | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature | +| images | pyexcel | image_two_cell_offset | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature | +| images | xlwt | image_one_cell | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter | +| images | xlwt | image_two_cell_offset | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter | +| images | pandas | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | pandas | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | pandas | image_one_cell | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | pandas | image_two_cell_offset | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | xlsxwriter-constmem | image_one_cell | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | xlsxwriter-constmem | image_two_cell_offset | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | openpyxl-readonly | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | openpyxl-readonly | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | polars | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | polars | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | tablib | image_one_cell | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | tablib | image_two_cell_offset | read | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| images | tablib | image_one_cell | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={} | +| images | tablib | image_two_cell_offset | write | data_mismatch | error | Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={} | +| comments | python-calamine | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | python-calamine | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | python-calamine | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | aspose-cells-foss | comment_legacy | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={'comment': {'cell': 'B2', 'text': 'None:Legacy note', 'threaded': False}} | +| comments | aspose-cells-foss | comment_threaded | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={'comment': {'cell': 'B3', 'text': 'None:Threaded fallback', 'threaded': False}} | +| comments | aspose-cells-foss | comment_author | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={'comment': {'cell': 'B4', 'text': 'None:Another note', 'threaded': False}} | +| comments | pylightxl | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | pylightxl | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | pylightxl | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | pylightxl | comment_legacy | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature | +| comments | pylightxl | comment_threaded | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature | +| comments | pylightxl | comment_author | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature | +| comments | pyexcel | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | pyexcel | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | pyexcel | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | pyexcel | comment_legacy | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature | +| comments | pyexcel | comment_threaded | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature | +| comments | pyexcel | comment_author | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature | +| comments | xlwt | comment_legacy | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments | +| comments | xlwt | comment_threaded | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments | +| comments | xlwt | comment_author | write | unsupported_feature | warning | UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments | +| comments | pandas | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | pandas | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | pandas | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | pandas | comment_legacy | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | pandas | comment_threaded | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | pandas | comment_author | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | xlsxwriter-constmem | comment_legacy | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | xlsxwriter-constmem | comment_threaded | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | xlsxwriter-constmem | comment_author | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | openpyxl-readonly | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | openpyxl-readonly | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | openpyxl-readonly | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | polars | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | polars | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | polars | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | tablib | comment_legacy | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | tablib | comment_threaded | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | tablib | comment_author | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| comments | tablib | comment_legacy | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={} | +| comments | tablib | comment_threaded | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={} | +| comments | tablib | comment_author | write | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={} | +| freeze_panes | python-calamine | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | python-calamine | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | python-calamine | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | pylightxl | freeze_b2 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| freeze_panes | pylightxl | freeze_d5 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| freeze_panes | pylightxl | split_2x1 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| freeze_panes | pylightxl | freeze_b2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature | +| freeze_panes | pylightxl | freeze_d5 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature | +| freeze_panes | pylightxl | split_2x1 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature | +| freeze_panes | pyexcel | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pyexcel | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pyexcel | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | pyexcel | freeze_b2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature | +| freeze_panes | pyexcel | freeze_d5 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature | +| freeze_panes | pyexcel | split_2x1 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature | +| freeze_panes | xlwt | freeze_b2 | write | internal | error | AttributeError: 'Sheet' object has no attribute 'frozen_row_count' | +| freeze_panes | xlwt | freeze_d5 | write | internal | error | AttributeError: 'Sheet' object has no attribute 'frozen_row_count' | +| freeze_panes | xlwt | split_2x1 | write | internal | error | AttributeError: 'Sheet' object has no attribute 'frozen_row_count' | +| freeze_panes | pandas | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pandas | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pandas | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | pandas | freeze_b2 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pandas | freeze_d5 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | pandas | split_2x1 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | openpyxl-readonly | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | openpyxl-readonly | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | openpyxl-readonly | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | polars | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | polars | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | polars | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | tablib | freeze_b2 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | tablib | freeze_d5 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | tablib | split_2x1 | read | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| freeze_panes | tablib | freeze_b2 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | tablib | freeze_d5 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}} | +| freeze_panes | tablib | split_2x1 | write | data_mismatch | error | Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}} | +| named_ranges | xlsxwriter | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | xlsxwriter | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | xlsxwriter | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | xlsxwriter | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | xlsxwriter | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | xlsxwriter | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement named range writes | +| named_ranges | python-calamine | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | python-calamine | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | python-calamine | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | python-calamine | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | python-calamine | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | python-calamine | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement named range reads | +| named_ranges | aspose-cells-foss | nr_sheet_scope | read | data_mismatch | error | Expected values did not match actual values: expected={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': 'local'}, actual={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': None} | +| named_ranges | wolfxl | nr_sheet_scope | write | data_mismatch | error | Expected values did not match actual values: expected={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': 'local'}, actual={'name': 'LocalName', 'scope': 'not_found', 'refers_to': ''} | +| named_ranges | pylightxl | nr_simple_cell | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_cell_range | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_formula_ref | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_sheet_scope | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_cross_sheet | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_special_chars | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pyexcel | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | xlwt | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | xlwt | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | xlwt | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | xlwt | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | xlwt | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | xlwt | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement named range writes | +| named_ranges | pandas | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | xlsxwriter-constmem | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement named range writes | +| named_ranges | openpyxl-readonly | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | openpyxl-readonly | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | openpyxl-readonly | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | openpyxl-readonly | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | openpyxl-readonly | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | openpyxl-readonly | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement named range reads | +| named_ranges | polars | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | polars | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | polars | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | polars | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | polars | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | polars | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: polars does not implement named range reads | +| named_ranges | tablib | nr_simple_cell | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_simple_cell | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| tables | xlsxwriter | tbl_basic | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | xlsxwriter | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | xlsxwriter | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | xlsxwriter | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | xlsxwriter | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | xlsxwriter | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement table writes | +| tables | python-calamine | tbl_basic | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | python-calamine | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | python-calamine | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | python-calamine | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | python-calamine | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | python-calamine | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement table reads | +| tables | aspose-cells-foss | tbl_with_totals | read | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}} | +| tables | aspose-cells-foss | tbl_no_style | read | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': None, 'columns': ['Key', 'Value']}}, actual={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium2', 'columns': ['Key', 'Value']}} | +| tables | aspose-cells-foss | tbl_with_totals | write | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}} | +| tables | aspose-cells-foss | tbl_no_style | write | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': None, 'columns': ['Key', 'Value']}}, actual={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium2', 'columns': ['Key', 'Value']}} | +| tables | pylightxl | tbl_basic | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_with_totals | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_no_style | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_single_col | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_single_row | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_autofilter | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_basic | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pyexcel | tbl_basic | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_basic | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | xlwt | tbl_basic | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | xlwt | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | xlwt | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | xlwt | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | xlwt | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | xlwt | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement table writes | +| tables | pandas | tbl_basic | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_basic | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | xlsxwriter-constmem | tbl_basic | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | xlsxwriter-constmem | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | xlsxwriter-constmem | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | xlsxwriter-constmem | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | xlsxwriter-constmem | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | xlsxwriter-constmem | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement table writes | +| tables | openpyxl-readonly | tbl_basic | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | openpyxl-readonly | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | openpyxl-readonly | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | openpyxl-readonly | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | openpyxl-readonly | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | openpyxl-readonly | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement table reads | +| tables | polars | tbl_basic | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | polars | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | polars | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | polars | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | polars | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | polars | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: polars does not implement table reads | +| tables | tablib | tbl_basic | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_basic | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| sheet_protection | xlsxwriter | prot_basic | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement sheet protection writes | +| sheet_protection | xlsxwriter | prot_password | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement sheet protection writes | +| sheet_protection | xlsxwriter | prot_granular | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement sheet protection writes | +| sheet_protection | python-calamine | prot_basic | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement sheet protection reads | +| sheet_protection | python-calamine | prot_password | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement sheet protection reads | +| sheet_protection | python-calamine | prot_granular | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement sheet protection reads | +| sheet_protection | pylightxl | prot_basic | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| sheet_protection | pylightxl | prot_password | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| sheet_protection | pylightxl | prot_granular | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| sheet_protection | pylightxl | prot_basic | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement sheet protection writes | +| sheet_protection | pylightxl | prot_password | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement sheet protection writes | +| sheet_protection | pylightxl | prot_granular | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement sheet protection writes | +| sheet_protection | pyexcel | prot_basic | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection reads | +| sheet_protection | pyexcel | prot_password | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection reads | +| sheet_protection | pyexcel | prot_granular | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection reads | +| sheet_protection | pyexcel | prot_basic | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection writes | +| sheet_protection | pyexcel | prot_password | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection writes | +| sheet_protection | pyexcel | prot_granular | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection writes | +| sheet_protection | xlwt | prot_basic | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement sheet protection writes | +| sheet_protection | xlwt | prot_password | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement sheet protection writes | +| sheet_protection | xlwt | prot_granular | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement sheet protection writes | +| sheet_protection | pandas | prot_basic | read | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection reads | +| sheet_protection | pandas | prot_password | read | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection reads | +| sheet_protection | pandas | prot_granular | read | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection reads | +| sheet_protection | pandas | prot_basic | write | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection writes | +| sheet_protection | pandas | prot_password | write | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection writes | +| sheet_protection | pandas | prot_granular | write | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection writes | +| sheet_protection | xlsxwriter-constmem | prot_basic | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes | +| sheet_protection | xlsxwriter-constmem | prot_password | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes | +| sheet_protection | xlsxwriter-constmem | prot_granular | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes | +| sheet_protection | openpyxl-readonly | prot_basic | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement sheet protection reads | +| sheet_protection | openpyxl-readonly | prot_password | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement sheet protection reads | +| sheet_protection | openpyxl-readonly | prot_granular | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement sheet protection reads | +| sheet_protection | polars | prot_basic | read | unsupported_feature | warning | NotImplementedError: polars does not implement sheet protection reads | +| sheet_protection | polars | prot_password | read | unsupported_feature | warning | NotImplementedError: polars does not implement sheet protection reads | +| sheet_protection | polars | prot_granular | read | unsupported_feature | warning | NotImplementedError: polars does not implement sheet protection reads | +| sheet_protection | tablib | prot_basic | read | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection reads | +| sheet_protection | tablib | prot_password | read | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection reads | +| sheet_protection | tablib | prot_granular | read | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection reads | +| sheet_protection | tablib | prot_basic | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| sheet_protection | tablib | prot_password | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| sheet_protection | tablib | prot_granular | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| page_setup | xlsxwriter | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement page setup writes | +| page_setup | xlsxwriter | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement page setup writes | +| page_setup | xlsxwriter | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement page setup writes | +| page_setup | python-calamine | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement page setup reads | +| page_setup | python-calamine | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement page setup reads | +| page_setup | python-calamine | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement page setup reads | +| page_setup | aspose-cells-foss | page_setup_landscape | read | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'landscape', 'fit_to_width': 1, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'landscape', 'fit_to_width': 1, 'fit_to_height': None, 'scale': 100, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | aspose-cells-foss | page_setup_titles | read | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 100, 'print_title_rows': None, 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}} | +| page_setup | aspose-cells-foss | page_setup_landscape | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API. | +| page_setup | aspose-cells-foss | page_setup_scale | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API. | +| page_setup | aspose-cells-foss | page_setup_titles | write | unsupported_feature | warning | UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API. | +| page_setup | wolfxl | page_setup_titles | write | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}, actual={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}} | +| page_setup | pylightxl | page_setup_landscape | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| page_setup | pylightxl | page_setup_scale | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| page_setup | pylightxl | page_setup_titles | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| page_setup | pylightxl | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement page setup writes | +| page_setup | pylightxl | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement page setup writes | +| page_setup | pylightxl | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement page setup writes | +| page_setup | pyexcel | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup reads | +| page_setup | pyexcel | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup reads | +| page_setup | pyexcel | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup reads | +| page_setup | pyexcel | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup writes | +| page_setup | pyexcel | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup writes | +| page_setup | pyexcel | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup writes | +| page_setup | xlwt | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement page setup writes | +| page_setup | xlwt | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement page setup writes | +| page_setup | xlwt | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement page setup writes | +| page_setup | pandas | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup reads | +| page_setup | pandas | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup reads | +| page_setup | pandas | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup reads | +| page_setup | pandas | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup writes | +| page_setup | pandas | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup writes | +| page_setup | pandas | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup writes | +| page_setup | xlsxwriter-constmem | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement page setup writes | +| page_setup | xlsxwriter-constmem | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement page setup writes | +| page_setup | xlsxwriter-constmem | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement page setup writes | +| page_setup | openpyxl-readonly | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement page setup reads | +| page_setup | openpyxl-readonly | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement page setup reads | +| page_setup | openpyxl-readonly | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement page setup reads | +| page_setup | polars | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: polars does not implement page setup reads | +| page_setup | polars | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: polars does not implement page setup reads | +| page_setup | polars | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: polars does not implement page setup reads | +| page_setup | tablib | page_setup_landscape | read | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup reads | +| page_setup | tablib | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup reads | +| page_setup | tablib | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup reads | +| page_setup | tablib | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| page_setup | tablib | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| page_setup | tablib | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| chart_anchor | xlsxwriter | chart_bar | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement chart anchor writes | +| chart_anchor | xlsxwriter | chart_line | write | unsupported_feature | warning | NotImplementedError: xlsxwriter does not implement chart anchor writes | +| chart_anchor | python-calamine | chart_bar | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement chart anchor reads | +| chart_anchor | python-calamine | chart_line | read | unsupported_feature | warning | NotImplementedError: python-calamine does not implement chart anchor reads | +| chart_anchor | pylightxl | chart_bar | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| chart_anchor | pylightxl | chart_line | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| chart_anchor | pylightxl | chart_bar | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement chart anchor writes | +| chart_anchor | pylightxl | chart_line | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement chart anchor writes | +| chart_anchor | pyexcel | chart_bar | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor reads | +| chart_anchor | pyexcel | chart_line | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor reads | +| chart_anchor | pyexcel | chart_bar | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor writes | +| chart_anchor | pyexcel | chart_line | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor writes | +| chart_anchor | xlwt | chart_bar | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement chart anchor writes | +| chart_anchor | xlwt | chart_line | write | unsupported_feature | warning | NotImplementedError: xlwt does not implement chart anchor writes | +| chart_anchor | pandas | chart_bar | read | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor reads | +| chart_anchor | pandas | chart_line | read | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor reads | +| chart_anchor | pandas | chart_bar | write | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor writes | +| chart_anchor | pandas | chart_line | write | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor writes | +| chart_anchor | xlsxwriter-constmem | chart_bar | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement chart anchor writes | +| chart_anchor | xlsxwriter-constmem | chart_line | write | unsupported_feature | warning | NotImplementedError: xlsxwriter-constmem does not implement chart anchor writes | +| chart_anchor | openpyxl-readonly | chart_bar | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement chart anchor reads | +| chart_anchor | openpyxl-readonly | chart_line | read | unsupported_feature | warning | NotImplementedError: openpyxl-readonly does not implement chart anchor reads | +| chart_anchor | polars | chart_bar | read | unsupported_feature | warning | NotImplementedError: polars does not implement chart anchor reads | +| chart_anchor | polars | chart_line | read | unsupported_feature | warning | NotImplementedError: polars does not implement chart anchor reads | +| chart_anchor | tablib | chart_bar | read | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor reads | +| chart_anchor | tablib | chart_line | read | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor reads | +| chart_anchor | tablib | chart_bar | write | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor writes | +| chart_anchor | tablib | chart_line | write | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor writes | + +## Detailed Results + + +### alignment + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🟠 1 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Align - left | basic | ✅ | ✅ | +| Align - center | basic | ✅ | ✅ | +| Align - right | basic | ✅ | ✅ | +| Align - top | basic | ✅ | ✅ | +| Align - center | basic | ✅ | ✅ | +| Align - bottom | basic | ❌ | ❌ | +| Align - wrap text | basic | ✅ | ✅ | +| Align - rotation 45 | basic | ✅ | ✅ | +| Align - indent 2 | basic | ✅ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Align - left | basic | ❌ | +| Align - center | basic | ❌ | +| Align - right | basic | ❌ | +| Align - top | basic | ❌ | +| Align - center | basic | ❌ | +| Align - bottom | basic | ❌ | +| Align - wrap text | basic | ❌ | +| Align - rotation 45 | basic | ❌ | +| Align - indent 2 | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Align - left | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - right | basic | ❌ | ❌ | +| Align - top | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - bottom | basic | ❌ | ❌ | +| Align - wrap text | basic | ❌ | ❌ | +| Align - rotation 45 | basic | ❌ | ❌ | +| Align - indent 2 | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Align - left | basic | ❌ | +| Align - center | basic | ❌ | +| Align - right | basic | ❌ | +| Align - top | basic | ❌ | +| Align - center | basic | ❌ | +| Align - bottom | basic | ❌ | +| Align - wrap text | basic | ❌ | +| Align - rotation 45 | basic | ❌ | +| Align - indent 2 | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Align - left | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - right | basic | ❌ | ❌ | +| Align - top | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - bottom | basic | ❌ | ❌ | +| Align - wrap text | basic | ❌ | ❌ | +| Align - rotation 45 | basic | ❌ | ❌ | +| Align - indent 2 | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 +- Notes: Known limitation: pylightxl alignment write is a no-op because the library does not support formatting writes. + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Align - left | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - right | basic | ❌ | ❌ | +| Align - top | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - bottom | basic | ❌ | ❌ | +| Align - wrap text | basic | ❌ | ❌ | +| Align - rotation 45 | basic | ❌ | ❌ | +| Align - indent 2 | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 +- Notes: Known limitation: python-calamine alignment read is limited because its API does not expose style/alignment metadata. + +| Test | Importance | Read | +|------|-----------|------| +| Align - left | basic | ❌ | +| Align - center | basic | ❌ | +| Align - right | basic | ❌ | +| Align - top | basic | ❌ | +| Align - center | basic | ❌ | +| Align - bottom | basic | ❌ | +| Align - wrap text | basic | ❌ | +| Align - rotation 45 | basic | ❌ | +| Align - indent 2 | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Align - left | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - right | basic | ❌ | ❌ | +| Align - top | basic | ❌ | ❌ | +| Align - center | basic | ❌ | ❌ | +| Align - bottom | basic | ❌ | ❌ | +| Align - wrap text | basic | ❌ | ❌ | +| Align - rotation 45 | basic | ❌ | ❌ | +| Align - indent 2 | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Align - left | basic | ✅ | +| Align - center | basic | ✅ | +| Align - right | basic | ✅ | +| Align - top | basic | ✅ | +| Align - center | basic | ✅ | +| Align - bottom | basic | ❌ | +| Align - wrap text | basic | ✅ | +| Align - rotation 45 | basic | ✅ | +| Align - indent 2 | basic | ✅ | + +**xlsxwriter-constmem** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Align - left | basic | ✅ | +| Align - center | basic | ✅ | +| Align - right | basic | ✅ | +| Align - top | basic | ✅ | +| Align - center | basic | ✅ | +| Align - bottom | basic | ❌ | +| Align - wrap text | basic | ✅ | +| Align - rotation 45 | basic | ✅ | +| Align - indent 2 | basic | ✅ | + +**xlwt** — Write: 🟢 3 + + +### background_colors + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Background - red | basic | ❌ | +| Background - blue | basic | ❌ | +| Background - green | basic | ❌ | +| Background - custom (#8B4513) | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Background - red | basic | ❌ | ❌ | +| Background - blue | basic | ❌ | ❌ | +| Background - green | basic | ❌ | ❌ | +| Background - custom (#8B4513) | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Background - red | basic | ❌ | +| Background - blue | basic | ❌ | +| Background - green | basic | ❌ | +| Background - custom (#8B4513) | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Background - red | basic | ❌ | ❌ | +| Background - blue | basic | ❌ | ❌ | +| Background - green | basic | ❌ | ❌ | +| Background - custom (#8B4513) | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Background - red | basic | ❌ | ❌ | +| Background - blue | basic | ❌ | ❌ | +| Background - green | basic | ❌ | ❌ | +| Background - custom (#8B4513) | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Background - red | basic | ❌ | +| Background - blue | basic | ❌ | +| Background - green | basic | ❌ | +| Background - custom (#8B4513) | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Background - red | basic | ❌ | ❌ | +| Background - blue | basic | ❌ | ❌ | +| Background - green | basic | ❌ | ❌ | +| Background - custom (#8B4513) | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Background - red | basic | ✅ | +| Background - blue | basic | ✅ | +| Background - green | basic | ❌ | +| Background - custom (#8B4513) | basic | ❌ | + + +### borders + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🟠 1 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Border - thin all edges | basic | ✅ | ✅ | +| Border - medium all edges | basic | ✅ | ✅ | +| Border - thick all edges | basic | ✅ | ✅ | +| Border - double line | basic | ✅ | ✅ | +| Border - dashed | basic | ✅ | ✅ | +| Border - dotted | basic | ✅ | ✅ | +| Border - dash-dot | basic | ✅ | ✅ | +| Border - dash-dot-dot | basic | ✅ | ✅ | +| Border - top only | basic | ✅ | ✅ | +| Border - bottom only | basic | ✅ | ✅ | +| Border - left only | basic | ✅ | ✅ | +| Border - right only | basic | ✅ | ✅ | +| Border - diagonal up | basic | ❌ | ❌ | +| Border - diagonal down | basic | ❌ | ❌ | +| Border - diagonal both | basic | ❌ | ❌ | +| Border - red color | basic | ✅ | ✅ | +| Border - blue color | basic | ✅ | ✅ | +| Border - custom color (#8B4513) | basic | ✅ | ✅ | +| Border - mixed styles per edge | basic | ✅ | ✅ | +| Border - mixed colors per edge | basic | ✅ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Border - thin all edges | basic | ❌ | +| Border - medium all edges | basic | ❌ | +| Border - thick all edges | basic | ❌ | +| Border - double line | basic | ❌ | +| Border - dashed | basic | ❌ | +| Border - dotted | basic | ❌ | +| Border - dash-dot | basic | ❌ | +| Border - dash-dot-dot | basic | ❌ | +| Border - top only | basic | ❌ | +| Border - bottom only | basic | ❌ | +| Border - left only | basic | ❌ | +| Border - right only | basic | ❌ | +| Border - diagonal up | basic | ❌ | +| Border - diagonal down | basic | ❌ | +| Border - diagonal both | basic | ❌ | +| Border - red color | basic | ❌ | +| Border - blue color | basic | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | +| Border - mixed styles per edge | basic | ❌ | +| Border - mixed colors per edge | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Border - thin all edges | basic | ❌ | ❌ | +| Border - medium all edges | basic | ❌ | ❌ | +| Border - thick all edges | basic | ❌ | ❌ | +| Border - double line | basic | ❌ | ❌ | +| Border - dashed | basic | ❌ | ❌ | +| Border - dotted | basic | ❌ | ❌ | +| Border - dash-dot | basic | ❌ | ❌ | +| Border - dash-dot-dot | basic | ❌ | ❌ | +| Border - top only | basic | ❌ | ❌ | +| Border - bottom only | basic | ❌ | ❌ | +| Border - left only | basic | ❌ | ❌ | +| Border - right only | basic | ❌ | ❌ | +| Border - diagonal up | basic | ❌ | ❌ | +| Border - diagonal down | basic | ❌ | ❌ | +| Border - diagonal both | basic | ❌ | ❌ | +| Border - red color | basic | ❌ | ❌ | +| Border - blue color | basic | ❌ | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | ❌ | +| Border - mixed styles per edge | basic | ❌ | ❌ | +| Border - mixed colors per edge | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Border - thin all edges | basic | ❌ | +| Border - medium all edges | basic | ❌ | +| Border - thick all edges | basic | ❌ | +| Border - double line | basic | ❌ | +| Border - dashed | basic | ❌ | +| Border - dotted | basic | ❌ | +| Border - dash-dot | basic | ❌ | +| Border - dash-dot-dot | basic | ❌ | +| Border - top only | basic | ❌ | +| Border - bottom only | basic | ❌ | +| Border - left only | basic | ❌ | +| Border - right only | basic | ❌ | +| Border - diagonal up | basic | ❌ | +| Border - diagonal down | basic | ❌ | +| Border - diagonal both | basic | ❌ | +| Border - red color | basic | ❌ | +| Border - blue color | basic | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | +| Border - mixed styles per edge | basic | ❌ | +| Border - mixed colors per edge | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Border - thin all edges | basic | ❌ | ❌ | +| Border - medium all edges | basic | ❌ | ❌ | +| Border - thick all edges | basic | ❌ | ❌ | +| Border - double line | basic | ❌ | ❌ | +| Border - dashed | basic | ❌ | ❌ | +| Border - dotted | basic | ❌ | ❌ | +| Border - dash-dot | basic | ❌ | ❌ | +| Border - dash-dot-dot | basic | ❌ | ❌ | +| Border - top only | basic | ❌ | ❌ | +| Border - bottom only | basic | ❌ | ❌ | +| Border - left only | basic | ❌ | ❌ | +| Border - right only | basic | ❌ | ❌ | +| Border - diagonal up | basic | ❌ | ❌ | +| Border - diagonal down | basic | ❌ | ❌ | +| Border - diagonal both | basic | ❌ | ❌ | +| Border - red color | basic | ❌ | ❌ | +| Border - blue color | basic | ❌ | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | ❌ | +| Border - mixed styles per edge | basic | ❌ | ❌ | +| Border - mixed colors per edge | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Border - thin all edges | basic | ❌ | ❌ | +| Border - medium all edges | basic | ❌ | ❌ | +| Border - thick all edges | basic | ❌ | ❌ | +| Border - double line | basic | ❌ | ❌ | +| Border - dashed | basic | ❌ | ❌ | +| Border - dotted | basic | ❌ | ❌ | +| Border - dash-dot | basic | ❌ | ❌ | +| Border - dash-dot-dot | basic | ❌ | ❌ | +| Border - top only | basic | ❌ | ❌ | +| Border - bottom only | basic | ❌ | ❌ | +| Border - left only | basic | ❌ | ❌ | +| Border - right only | basic | ❌ | ❌ | +| Border - diagonal up | basic | ❌ | ❌ | +| Border - diagonal down | basic | ❌ | ❌ | +| Border - diagonal both | basic | ❌ | ❌ | +| Border - red color | basic | ❌ | ❌ | +| Border - blue color | basic | ❌ | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | ❌ | +| Border - mixed styles per edge | basic | ❌ | ❌ | +| Border - mixed colors per edge | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Border - thin all edges | basic | ❌ | +| Border - medium all edges | basic | ❌ | +| Border - thick all edges | basic | ❌ | +| Border - double line | basic | ❌ | +| Border - dashed | basic | ❌ | +| Border - dotted | basic | ❌ | +| Border - dash-dot | basic | ❌ | +| Border - dash-dot-dot | basic | ❌ | +| Border - top only | basic | ❌ | +| Border - bottom only | basic | ❌ | +| Border - left only | basic | ❌ | +| Border - right only | basic | ❌ | +| Border - diagonal up | basic | ❌ | +| Border - diagonal down | basic | ❌ | +| Border - diagonal both | basic | ❌ | +| Border - red color | basic | ❌ | +| Border - blue color | basic | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | +| Border - mixed styles per edge | basic | ❌ | +| Border - mixed colors per edge | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Border - thin all edges | basic | ❌ | ❌ | +| Border - medium all edges | basic | ❌ | ❌ | +| Border - thick all edges | basic | ❌ | ❌ | +| Border - double line | basic | ❌ | ❌ | +| Border - dashed | basic | ❌ | ❌ | +| Border - dotted | basic | ❌ | ❌ | +| Border - dash-dot | basic | ❌ | ❌ | +| Border - dash-dot-dot | basic | ❌ | ❌ | +| Border - top only | basic | ❌ | ❌ | +| Border - bottom only | basic | ❌ | ❌ | +| Border - left only | basic | ❌ | ❌ | +| Border - right only | basic | ❌ | ❌ | +| Border - diagonal up | basic | ❌ | ❌ | +| Border - diagonal down | basic | ❌ | ❌ | +| Border - diagonal both | basic | ❌ | ❌ | +| Border - red color | basic | ❌ | ❌ | +| Border - blue color | basic | ❌ | ❌ | +| Border - custom color (#8B4513) | basic | ❌ | ❌ | +| Border - mixed styles per edge | basic | ❌ | ❌ | +| Border - mixed colors per edge | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Border - thin all edges | basic | ✅ | +| Border - medium all edges | basic | ✅ | +| Border - thick all edges | basic | ✅ | +| Border - double line | basic | ✅ | +| Border - dashed | basic | ✅ | +| Border - dotted | basic | ✅ | +| Border - dash-dot | basic | ✅ | +| Border - dash-dot-dot | basic | ✅ | +| Border - top only | basic | ✅ | +| Border - bottom only | basic | ✅ | +| Border - left only | basic | ✅ | +| Border - right only | basic | ✅ | +| Border - diagonal up | basic | ❌ | +| Border - diagonal down | basic | ❌ | +| Border - diagonal both | basic | ✅ | +| Border - red color | basic | ✅ | +| Border - blue color | basic | ✅ | +| Border - custom color (#8B4513) | basic | ❌ | +| Border - mixed styles per edge | basic | ✅ | +| Border - mixed colors per edge | basic | ❌ | + + +### cell_values + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| String - simple | basic | ✅ | ✅ | +| String - unicode | basic | ✅ | ✅ | +| String - empty | basic | ✅ | ✅ | +| String - long (1000 chars) | basic | ✅ | ✅ | +| String - with newlines | basic | ✅ | ✅ | +| Number - integer | basic | ✅ | ✅ | +| Number - float | basic | ✅ | ✅ | +| Number - negative | basic | ✅ | ✅ | +| Number - large | basic | ✅ | ✅ | +| Number - scientific notation | basic | ✅ | ✅ | +| Date - standard | basic | ❌ | ✅ | +| DateTime - with time | basic | ❌ | ✅ | +| Boolean - TRUE | basic | ✅ | ✅ | +| Boolean - FALSE | basic | ✅ | ✅ | +| Error - #DIV/0! | basic | ✅ | ✅ | +| Error - #N/A | basic | ✅ | ✅ | +| Error - #VALUE! | basic | ✅ | ✅ | +| Blank cell | basic | ✅ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🟢 3 + +**pandas** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| String - simple | basic | ✅ | ✅ | +| String - unicode | basic | ✅ | ✅ | +| String - empty | basic | ✅ | ✅ | +| String - long (1000 chars) | basic | ✅ | ✅ | +| String - with newlines | basic | ✅ | ✅ | +| Number - integer | basic | ✅ | ✅ | +| Number - float | basic | ✅ | ✅ | +| Number - negative | basic | ✅ | ✅ | +| Number - large | basic | ✅ | ✅ | +| Number - scientific notation | basic | ✅ | ✅ | +| Date - standard | basic | ✅ | ✅ | +| DateTime - with time | basic | ✅ | ✅ | +| Boolean - TRUE | basic | ✅ | ✅ | +| Boolean - FALSE | basic | ✅ | ✅ | +| Error - #DIV/0! | basic | ❌ | ✅ | +| Error - #N/A | basic | ❌ | ✅ | +| Error - #VALUE! | basic | ❌ | ✅ | +| Blank cell | basic | ✅ | ✅ | + +**polars** — Read: 🟠 1 + +| Test | Importance | Read | +|------|-----------|------| +| String - simple | basic | ✅ | +| String - unicode | basic | ✅ | +| String - empty | basic | ✅ | +| String - long (1000 chars) | basic | ✅ | +| String - with newlines | basic | ✅ | +| Number - integer | basic | ✅ | +| Number - float | basic | ✅ | +| Number - negative | basic | ✅ | +| Number - large | basic | ✅ | +| Number - scientific notation | basic | ✅ | +| Date - standard | basic | ✅ | +| DateTime - with time | basic | ✅ | +| Boolean - TRUE | basic | ✅ | +| Boolean - FALSE | basic | ✅ | +| Error - #DIV/0! | basic | ❌ | +| Error - #N/A | basic | ❌ | +| Error - #VALUE! | basic | ❌ | +| Blank cell | basic | ✅ | + +**pyexcel** — Read: 🟢 3 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| String - simple | basic | ✅ | ❌ | +| String - unicode | basic | ✅ | ❌ | +| String - empty | basic | ✅ | ❌ | +| String - long (1000 chars) | basic | ✅ | ❌ | +| String - with newlines | basic | ✅ | ❌ | +| Number - integer | basic | ✅ | ❌ | +| Number - float | basic | ✅ | ❌ | +| Number - negative | basic | ✅ | ❌ | +| Number - large | basic | ✅ | ❌ | +| Number - scientific notation | basic | ✅ | ❌ | +| Date - standard | basic | ✅ | ❌ | +| DateTime - with time | basic | ✅ | ❌ | +| Boolean - TRUE | basic | ✅ | ❌ | +| Boolean - FALSE | basic | ✅ | ❌ | +| Error - #DIV/0! | basic | ✅ | ❌ | +| Error - #N/A | basic | ✅ | ❌ | +| Error - #VALUE! | basic | ✅ | ❌ | +| Blank cell | basic | ✅ | ❌ | + +**pylightxl** — Read: 🟢 3 | Write: 🔴 0 +- Notes: Known limitation: pylightxl cell-values write has date/boolean/error fidelity limits due to writer encoding behavior. + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| String - simple | basic | ✅ | ❌ | +| String - unicode | basic | ✅ | ❌ | +| String - empty | basic | ✅ | ❌ | +| String - long (1000 chars) | basic | ✅ | ❌ | +| String - with newlines | basic | ✅ | ❌ | +| Number - integer | basic | ✅ | ❌ | +| Number - float | basic | ✅ | ❌ | +| Number - negative | basic | ✅ | ❌ | +| Number - large | basic | ✅ | ❌ | +| Number - scientific notation | basic | ✅ | ❌ | +| Date - standard | basic | ✅ | ❌ | +| DateTime - with time | basic | ✅ | ❌ | +| Boolean - TRUE | basic | ✅ | ❌ | +| Boolean - FALSE | basic | ✅ | ❌ | +| Error - #DIV/0! | basic | ✅ | ❌ | +| Error - #N/A | basic | ✅ | ❌ | +| Error - #VALUE! | basic | ✅ | ❌ | +| Blank cell | basic | ✅ | ❌ | + +**python-calamine** — Read: 🟠 1 +- Notes: Known limitation: python-calamine can surface formula error cells as blank values in current API responses. + +| Test | Importance | Read | +|------|-----------|------| +| String - simple | basic | ✅ | +| String - unicode | basic | ✅ | +| String - empty | basic | ✅ | +| String - long (1000 chars) | basic | ✅ | +| String - with newlines | basic | ✅ | +| Number - integer | basic | ✅ | +| Number - float | basic | ✅ | +| Number - negative | basic | ✅ | +| Number - large | basic | ✅ | +| Number - scientific notation | basic | ✅ | +| Date - standard | basic | ✅ | +| DateTime - with time | basic | ✅ | +| Boolean - TRUE | basic | ✅ | +| Boolean - FALSE | basic | ✅ | +| Error - #DIV/0! | basic | ❌ | +| Error - #N/A | basic | ❌ | +| Error - #VALUE! | basic | ❌ | +| Blank cell | basic | ✅ | + +**tablib** — Read: 🟢 3 | Write: 🟢 3 + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟢 3 + + +### chart_anchor + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + + +### comments + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Comment: legacy note | basic | ✅ | ❌ | +| Comment: threaded | edge | ✅ | ❌ | +| Comment: second author | edge | ✅ | ❌ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Comment: legacy note | basic | ❌ | +| Comment: threaded | edge | ❌ | +| Comment: second author | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Comment: legacy note | basic | ❌ | ❌ | +| Comment: threaded | edge | ❌ | ❌ | +| Comment: second author | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Comment: legacy note | basic | ❌ | +| Comment: threaded | edge | ❌ | +| Comment: second author | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Comment: legacy note | basic | ❌ | ❌ | +| Comment: threaded | edge | ❌ | ❌ | +| Comment: second author | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Comment: legacy note | basic | ❌ | ❌ | +| Comment: threaded | edge | ❌ | ❌ | +| Comment: second author | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Comment: legacy note | basic | ❌ | +| Comment: threaded | edge | ❌ | +| Comment: second author | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Comment: legacy note | basic | ❌ | ❌ | +| Comment: threaded | edge | ❌ | ❌ | +| Comment: second author | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Comment: legacy note | basic | ❌ | +| Comment: threaded | edge | ❌ | +| Comment: second author | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Comment: legacy note | basic | ❌ | +| Comment: threaded | edge | ❌ | +| Comment: second author | edge | ❌ | + + +### conditional_formatting + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| CF: cell > 5 (yellow fill) | basic | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | +| CF: text contains | edge | ❌ | +| CF: data bar | edge | ❌ | +| CF: 3-color scale | edge | ❌ | +| CF: stop-if-true priority | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | ❌ | +| CF: text contains | edge | ❌ | ❌ | +| CF: data bar | edge | ❌ | ❌ | +| CF: 3-color scale | edge | ❌ | ❌ | +| CF: stop-if-true priority | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| CF: cell > 5 (yellow fill) | basic | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | +| CF: text contains | edge | ❌ | +| CF: data bar | edge | ❌ | +| CF: 3-color scale | edge | ❌ | +| CF: stop-if-true priority | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | ❌ | +| CF: text contains | edge | ❌ | ❌ | +| CF: data bar | edge | ❌ | ❌ | +| CF: 3-color scale | edge | ❌ | ❌ | +| CF: stop-if-true priority | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | ❌ | +| CF: text contains | edge | ❌ | ❌ | +| CF: data bar | edge | ❌ | ❌ | +| CF: 3-color scale | edge | ❌ | ❌ | +| CF: stop-if-true priority | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| CF: cell > 5 (yellow fill) | basic | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | +| CF: text contains | edge | ❌ | +| CF: data bar | edge | ❌ | +| CF: 3-color scale | edge | ❌ | +| CF: stop-if-true priority | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | ❌ | +| CF: text contains | edge | ❌ | ❌ | +| CF: data bar | edge | ❌ | ❌ | +| CF: 3-color scale | edge | ❌ | ❌ | +| CF: stop-if-true priority | edge | ❌ | ❌ | + +**wolfxl** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | ✅ | +| CF: formula rule with cross-sheet ref | edge | ❌ | ✅ | +| CF: text contains | edge | ❌ | ✅ | +| CF: data bar | edge | ✅ | ✅ | +| CF: 3-color scale | edge | ✅ | ✅ | +| CF: stop-if-true priority | edge | ❌ | ✅ | + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| CF: cell > 5 (yellow fill) | basic | ❌ | +| CF: formula rule with cross-sheet ref | edge | ❌ | +| CF: text contains | edge | ❌ | +| CF: data bar | edge | ❌ | +| CF: 3-color scale | edge | ❌ | +| CF: stop-if-true priority | edge | ❌ | + + +### data_validation + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| DV: list from CSV | basic | ❌ | +| DV: list from range | edge | ❌ | +| DV: cross-sheet named range | edge | ❌ | +| DV: custom formula | edge | ❌ | +| DV: whole number with error | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| DV: list from CSV | basic | ❌ | ❌ | +| DV: list from range | edge | ❌ | ❌ | +| DV: cross-sheet named range | edge | ❌ | ❌ | +| DV: custom formula | edge | ❌ | ❌ | +| DV: whole number with error | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| DV: list from CSV | basic | ❌ | +| DV: list from range | edge | ❌ | +| DV: cross-sheet named range | edge | ❌ | +| DV: custom formula | edge | ❌ | +| DV: whole number with error | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| DV: list from CSV | basic | ❌ | ❌ | +| DV: list from range | edge | ❌ | ❌ | +| DV: cross-sheet named range | edge | ❌ | ❌ | +| DV: custom formula | edge | ❌ | ❌ | +| DV: whole number with error | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| DV: list from CSV | basic | ❌ | ❌ | +| DV: list from range | edge | ❌ | ❌ | +| DV: cross-sheet named range | edge | ❌ | ❌ | +| DV: custom formula | edge | ❌ | ❌ | +| DV: whole number with error | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| DV: list from CSV | basic | ❌ | +| DV: list from range | edge | ❌ | +| DV: cross-sheet named range | edge | ❌ | +| DV: custom formula | edge | ❌ | +| DV: whole number with error | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| DV: list from CSV | basic | ❌ | ❌ | +| DV: list from range | edge | ❌ | ❌ | +| DV: cross-sheet named range | edge | ❌ | ❌ | +| DV: custom formula | edge | ❌ | ❌ | +| DV: whole number with error | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| DV: list from CSV | basic | ❌ | +| DV: list from range | edge | ❌ | +| DV: cross-sheet named range | edge | ❌ | +| DV: custom formula | edge | ❌ | +| DV: whole number with error | basic | ❌ | + + +### dimensions + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Row height - 30 | basic | ✅ | ✅ | +| Row height - 45 | basic | ✅ | ✅ | +| Column width - D = 20 | basic | ❌ | ✅ | +| Column width - E = 8 | basic | ❌ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ❌ | +| Column width - E = 8 | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Row height - 30 | basic | ❌ | ❌ | +| Row height - 45 | basic | ❌ | ❌ | +| Column width - D = 20 | basic | ❌ | ❌ | +| Column width - E = 8 | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ❌ | +| Column width - E = 8 | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Row height - 30 | basic | ❌ | ❌ | +| Row height - 45 | basic | ❌ | ❌ | +| Column width - D = 20 | basic | ❌ | ❌ | +| Column width - E = 8 | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Row height - 30 | basic | ❌ | ❌ | +| Row height - 45 | basic | ❌ | ❌ | +| Column width - D = 20 | basic | ❌ | ❌ | +| Column width - E = 8 | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ❌ | +| Column width - E = 8 | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Row height - 30 | basic | ❌ | ❌ | +| Row height - 45 | basic | ❌ | ❌ | +| Column width - D = 20 | basic | ❌ | ❌ | +| Column width - E = 8 | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ✅ | +| Column width - E = 8 | basic | ✅ | + +**xlwt** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Row height - 30 | basic | ❌ | +| Row height - 45 | basic | ❌ | +| Column width - D = 20 | basic | ✅ | +| Column width - E = 8 | basic | ✅ | + + +### formulas + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🟢 3 + +**pandas** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ❌ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ❌ | ✅ | +| Formula - cross sheet | basic | ❌ | ✅ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Formula - SUM | basic | ❌ | +| Formula - cell reference | basic | ❌ | +| Formula - concat | basic | ❌ | +| Formula - cross sheet | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ❌ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ❌ | ✅ | +| Formula - cross sheet | basic | ❌ | ✅ | + +**pylightxl** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ❌ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ❌ | ✅ | +| Formula - cross sheet | basic | ❌ | ✅ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Formula - SUM | basic | ❌ | +| Formula - cell reference | basic | ❌ | +| Formula - concat | basic | ❌ | +| Formula - cross sheet | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ❌ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ❌ | ✅ | +| Formula - cross sheet | basic | ❌ | ✅ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Formula - SUM | basic | ❌ | +| Formula - cell reference | basic | ❌ | +| Formula - concat | basic | ❌ | +| Formula - cross sheet | basic | ❌ | + + +### freeze_panes + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Freeze panes at B2 | basic | ❌ | +| Freeze panes at D5 | edge | ❌ | +| Split panes row=2 col=1 | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Freeze panes at B2 | basic | ❌ | ❌ | +| Freeze panes at D5 | edge | ❌ | ❌ | +| Split panes row=2 col=1 | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Freeze panes at B2 | basic | ❌ | +| Freeze panes at D5 | edge | ❌ | +| Split panes row=2 col=1 | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Freeze panes at B2 | basic | ❌ | ❌ | +| Freeze panes at D5 | edge | ❌ | ❌ | +| Split panes row=2 col=1 | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Freeze panes at B2 | basic | ❌ | ❌ | +| Freeze panes at D5 | edge | ❌ | ❌ | +| Split panes row=2 col=1 | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Freeze panes at B2 | basic | ❌ | +| Freeze panes at D5 | edge | ❌ | +| Split panes row=2 col=1 | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Freeze panes at B2 | basic | ❌ | ❌ | +| Freeze panes at D5 | edge | ❌ | ❌ | +| Split panes row=2 col=1 | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Freeze panes at B2 | basic | ❌ | +| Freeze panes at D5 | edge | ❌ | +| Split panes row=2 col=1 | edge | ❌ | + + +### hyperlinks + +**aspose-cells-foss** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ✅ | +| Hyperlink: internal sheet | edge | ❌ | ✅ | +| Hyperlink: mailto | basic | ❌ | ✅ | +| Hyperlink: long encoded URL | edge | ❌ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ❌ | +| Hyperlink: internal sheet | edge | ❌ | ❌ | +| Hyperlink: mailto | basic | ❌ | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ❌ | +| Hyperlink: internal sheet | edge | ❌ | ❌ | +| Hyperlink: mailto | basic | ❌ | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ❌ | +| Hyperlink: internal sheet | edge | ❌ | ❌ | +| Hyperlink: mailto | basic | ❌ | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ❌ | +| Hyperlink: internal sheet | edge | ❌ | ❌ | +| Hyperlink: mailto | basic | ❌ | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + + +### images + +**aspose-cells-foss** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + + +### merged_cells + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Merge horizontal B2:D2 | basic | ❌ | +| Merge vertical B3:B5 | basic | ❌ | +| Merge with non-top-left value | edge | ❌ | +| Merge with top-left fill | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Merge horizontal B2:D2 | basic | ❌ | ❌ | +| Merge vertical B3:B5 | basic | ❌ | ❌ | +| Merge with non-top-left value | edge | ❌ | ❌ | +| Merge with top-left fill | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Merge horizontal B2:D2 | basic | ❌ | +| Merge vertical B3:B5 | basic | ❌ | +| Merge with non-top-left value | edge | ❌ | +| Merge with top-left fill | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Merge horizontal B2:D2 | basic | ❌ | ❌ | +| Merge vertical B3:B5 | basic | ❌ | ❌ | +| Merge with non-top-left value | edge | ❌ | ❌ | +| Merge with top-left fill | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Merge horizontal B2:D2 | basic | ❌ | ❌ | +| Merge vertical B3:B5 | basic | ❌ | ❌ | +| Merge with non-top-left value | edge | ❌ | ❌ | +| Merge with top-left fill | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Merge horizontal B2:D2 | basic | ❌ | +| Merge vertical B3:B5 | basic | ❌ | +| Merge with non-top-left value | edge | ❌ | +| Merge with top-left fill | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Merge horizontal B2:D2 | basic | ❌ | ❌ | +| Merge vertical B3:B5 | basic | ❌ | ❌ | +| Merge with non-top-left value | edge | ❌ | ❌ | +| Merge with top-left fill | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Merge horizontal B2:D2 | basic | ❌ | +| Merge vertical B3:B5 | basic | ❌ | +| Merge with non-top-left value | edge | ❌ | +| Merge with top-left fill | edge | ❌ | + + +### multiple_sheets + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🟢 3 + +**pandas** — Read: 🟢 3 | Write: 🟢 3 + +**polars** — Read: 🟠 1 + +| Test | Importance | Read | +|------|-----------|------| +| Sheet names | basic | ✅ | +| Alpha value | basic | ✅ | +| Beta value | basic | ❌ | +| Gamma value | basic | ❌ | + +**pyexcel** — Read: 🟢 3 | Write: 🟢 3 + +**pylightxl** — Read: 🟢 3 | Write: 🟢 3 + +**python-calamine** — Read: 🟢 3 + +**tablib** — Read: 🟢 3 | Write: 🟢 3 + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟢 3 + + +### named_ranges + +**aspose-cells-foss** — Read: 🟡 2 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ✅ | ✅ | +| Named range: cell range | basic | ✅ | ✅ | +| Named range: used in formula | basic | ✅ | ✅ | +| Named range: sheet-scoped | edge | ❌ | ✅ | +| Named range: cross-sheet reference | edge | ✅ | ✅ | +| Named range: underscore name | edge | ✅ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ❌ | ❌ | +| Named range: cell range | basic | ❌ | ❌ | +| Named range: used in formula | basic | ❌ | ❌ | +| Named range: sheet-scoped | edge | ❌ | ❌ | +| Named range: cross-sheet reference | edge | ❌ | ❌ | +| Named range: underscore name | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ❌ | ❌ | +| Named range: cell range | basic | ❌ | ❌ | +| Named range: used in formula | basic | ❌ | ❌ | +| Named range: sheet-scoped | edge | ❌ | ❌ | +| Named range: cross-sheet reference | edge | ❌ | ❌ | +| Named range: underscore name | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ❌ | ❌ | +| Named range: cell range | basic | ❌ | ❌ | +| Named range: used in formula | basic | ❌ | ❌ | +| Named range: sheet-scoped | edge | ❌ | ❌ | +| Named range: cross-sheet reference | edge | ❌ | ❌ | +| Named range: underscore name | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ❌ | ❌ | +| Named range: cell range | basic | ❌ | ❌ | +| Named range: used in formula | basic | ❌ | ❌ | +| Named range: sheet-scoped | edge | ❌ | ❌ | +| Named range: cross-sheet reference | edge | ❌ | ❌ | +| Named range: underscore name | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟡 2 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Named range: single cell | basic | ✅ | ✅ | +| Named range: cell range | basic | ✅ | ✅ | +| Named range: used in formula | basic | ✅ | ✅ | +| Named range: sheet-scoped | edge | ✅ | ❌ | +| Named range: cross-sheet reference | edge | ✅ | ✅ | +| Named range: underscore name | edge | ✅ | ✅ | + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Named range: single cell | basic | ❌ | +| Named range: cell range | basic | ❌ | +| Named range: used in formula | basic | ❌ | +| Named range: sheet-scoped | edge | ❌ | +| Named range: cross-sheet reference | edge | ❌ | +| Named range: underscore name | edge | ❌ | + + +### number_formats + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Format - currency | basic | ❌ | +| Format - percent | basic | ❌ | +| Format - date | basic | ❌ | +| Format - scientific | basic | ❌ | +| Format - custom text | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Format - currency | basic | ❌ | ❌ | +| Format - percent | basic | ❌ | ❌ | +| Format - date | basic | ❌ | ❌ | +| Format - scientific | basic | ❌ | ❌ | +| Format - custom text | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Format - currency | basic | ❌ | +| Format - percent | basic | ❌ | +| Format - date | basic | ❌ | +| Format - scientific | basic | ❌ | +| Format - custom text | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Format - currency | basic | ❌ | ❌ | +| Format - percent | basic | ❌ | ❌ | +| Format - date | basic | ❌ | ❌ | +| Format - scientific | basic | ❌ | ❌ | +| Format - custom text | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Format - currency | basic | ❌ | ❌ | +| Format - percent | basic | ❌ | ❌ | +| Format - date | basic | ❌ | ❌ | +| Format - scientific | basic | ❌ | ❌ | +| Format - custom text | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Format - currency | basic | ❌ | +| Format - percent | basic | ❌ | +| Format - date | basic | ❌ | +| Format - scientific | basic | ❌ | +| Format - custom text | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Format - currency | basic | ❌ | ❌ | +| Format - percent | basic | ❌ | ❌ | +| Format - date | basic | ❌ | ❌ | +| Format - scientific | basic | ❌ | ❌ | +| Format - custom text | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟢 3 + + +### page_setup + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | ❌ | +| Page setup: portrait at 75% scale | basic | ✅ | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | ❌ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟡 2 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Page setup: landscape + fit-to-width | basic | ✅ | ✅ | +| Page setup: portrait at 75% scale | basic | ✅ | ✅ | +| Page setup: print titles + header/footer | edge | ✅ | ❌ | + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Page setup: landscape + fit-to-width | basic | ❌ | +| Page setup: portrait at 75% scale | basic | ❌ | +| Page setup: print titles + header/footer | edge | ❌ | + + +### pivot_tables + +**aspose-cells-foss** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**openpyxl** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**openpyxl-readonly** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**pandas** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**polars** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**pyexcel** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**pylightxl** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**python-calamine** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**tablib** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**wolfxl** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**xlsxwriter-constmem** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**xlwt** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + + +### sheet_protection + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | ❌ | +| Protection: with password hash | basic | ❌ | ❌ | +| Protection: granular attribute flags | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | ❌ | +| Protection: with password hash | basic | ❌ | ❌ | +| Protection: granular attribute flags | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | ❌ | +| Protection: with password hash | basic | ❌ | ❌ | +| Protection: granular attribute flags | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | ❌ | +| Protection: with password hash | basic | ❌ | ❌ | +| Protection: granular attribute flags | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + + +### tables + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🟠 1 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Table: basic 3-col | basic | ✅ | ✅ | +| Table: with totals row | basic | ❌ | ❌ | +| Table: no style | basic | ❌ | ❌ | +| Table: single column | edge | ✅ | ✅ | +| Table: header only (no data rows) | edge | ✅ | ✅ | +| Table: with autoFilter | edge | ✅ | ✅ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Table: basic 3-col | basic | ❌ | ❌ | +| Table: with totals row | basic | ❌ | ❌ | +| Table: no style | basic | ❌ | ❌ | +| Table: single column | edge | ❌ | ❌ | +| Table: header only (no data rows) | edge | ❌ | ❌ | +| Table: with autoFilter | edge | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Table: basic 3-col | basic | ❌ | ❌ | +| Table: with totals row | basic | ❌ | ❌ | +| Table: no style | basic | ❌ | ❌ | +| Table: single column | edge | ❌ | ❌ | +| Table: header only (no data rows) | edge | ❌ | ❌ | +| Table: with autoFilter | edge | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Table: basic 3-col | basic | ❌ | ❌ | +| Table: with totals row | basic | ❌ | ❌ | +| Table: no style | basic | ❌ | ❌ | +| Table: single column | edge | ❌ | ❌ | +| Table: header only (no data rows) | edge | ❌ | ❌ | +| Table: with autoFilter | edge | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Table: basic 3-col | basic | ❌ | ❌ | +| Table: with totals row | basic | ❌ | ❌ | +| Table: no style | basic | ❌ | ❌ | +| Table: single column | edge | ❌ | ❌ | +| Table: header only (no data rows) | edge | ❌ | ❌ | +| Table: with autoFilter | edge | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + +**xlsxwriter-constmem** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + +**xlwt** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Table: basic 3-col | basic | ❌ | +| Table: with totals row | basic | ❌ | +| Table: no style | basic | ❌ | +| Table: single column | edge | ❌ | +| Table: header only (no data rows) | edge | ❌ | +| Table: with autoFilter | edge | ❌ | + + +### text_formatting + +**aspose-cells-foss** — Read: 🟠 1 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Bold | basic | ✅ | ❌ | +| Italic | basic | ✅ | ❌ | +| Underline - single | basic | ✅ | ❌ | +| Underline - double | basic | ❌ | ❌ | +| Strikethrough | basic | ✅ | ❌ | +| Bold + Italic | basic | ✅ | ❌ | +| Font size 8 | basic | ✅ | ❌ | +| Font size 14 | basic | ✅ | ❌ | +| Font size 24 | basic | ✅ | ❌ | +| Font size 36 | basic | ✅ | ❌ | +| Font - Arial | basic | ✅ | ❌ | +| Font - Times New Roman | basic | ✅ | ❌ | +| Font - Courier New | basic | ✅ | ❌ | +| Font color - red | basic | ✅ | ❌ | +| Font color - blue | basic | ✅ | ❌ | +| Font color - green | basic | ✅ | ❌ | +| Font color - custom (#8B4513) | basic | ✅ | ❌ | +| Combined - bold, 16pt, red | basic | ✅ | ❌ | + +**openpyxl** — Read: 🟢 3 | Write: 🟢 3 + +**openpyxl-readonly** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Bold | basic | ❌ | +| Italic | basic | ❌ | +| Underline - single | basic | ❌ | +| Underline - double | basic | ❌ | +| Strikethrough | basic | ❌ | +| Bold + Italic | basic | ❌ | +| Font size 8 | basic | ❌ | +| Font size 14 | basic | ❌ | +| Font size 24 | basic | ❌ | +| Font size 36 | basic | ❌ | +| Font - Arial | basic | ❌ | +| Font - Times New Roman | basic | ❌ | +| Font - Courier New | basic | ❌ | +| Font color - red | basic | ❌ | +| Font color - blue | basic | ❌ | +| Font color - green | basic | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | + +**pandas** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Bold | basic | ❌ | ❌ | +| Italic | basic | ❌ | ❌ | +| Underline - single | basic | ❌ | ❌ | +| Underline - double | basic | ❌ | ❌ | +| Strikethrough | basic | ❌ | ❌ | +| Bold + Italic | basic | ❌ | ❌ | +| Font size 8 | basic | ❌ | ❌ | +| Font size 14 | basic | ❌ | ❌ | +| Font size 24 | basic | ❌ | ❌ | +| Font size 36 | basic | ❌ | ❌ | +| Font - Arial | basic | ❌ | ❌ | +| Font - Times New Roman | basic | ❌ | ❌ | +| Font - Courier New | basic | ❌ | ❌ | +| Font color - red | basic | ❌ | ❌ | +| Font color - blue | basic | ❌ | ❌ | +| Font color - green | basic | ❌ | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | ❌ | + +**polars** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Bold | basic | ❌ | +| Italic | basic | ❌ | +| Underline - single | basic | ❌ | +| Underline - double | basic | ❌ | +| Strikethrough | basic | ❌ | +| Bold + Italic | basic | ❌ | +| Font size 8 | basic | ❌ | +| Font size 14 | basic | ❌ | +| Font size 24 | basic | ❌ | +| Font size 36 | basic | ❌ | +| Font - Arial | basic | ❌ | +| Font - Times New Roman | basic | ❌ | +| Font - Courier New | basic | ❌ | +| Font color - red | basic | ❌ | +| Font color - blue | basic | ❌ | +| Font color - green | basic | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | + +**pyexcel** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Bold | basic | ❌ | ❌ | +| Italic | basic | ❌ | ❌ | +| Underline - single | basic | ❌ | ❌ | +| Underline - double | basic | ❌ | ❌ | +| Strikethrough | basic | ❌ | ❌ | +| Bold + Italic | basic | ❌ | ❌ | +| Font size 8 | basic | ❌ | ❌ | +| Font size 14 | basic | ❌ | ❌ | +| Font size 24 | basic | ❌ | ❌ | +| Font size 36 | basic | ❌ | ❌ | +| Font - Arial | basic | ❌ | ❌ | +| Font - Times New Roman | basic | ❌ | ❌ | +| Font - Courier New | basic | ❌ | ❌ | +| Font color - red | basic | ❌ | ❌ | +| Font color - blue | basic | ❌ | ❌ | +| Font color - green | basic | ❌ | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | ❌ | + +**pylightxl** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Bold | basic | ❌ | ❌ | +| Italic | basic | ❌ | ❌ | +| Underline - single | basic | ❌ | ❌ | +| Underline - double | basic | ❌ | ❌ | +| Strikethrough | basic | ❌ | ❌ | +| Bold + Italic | basic | ❌ | ❌ | +| Font size 8 | basic | ❌ | ❌ | +| Font size 14 | basic | ❌ | ❌ | +| Font size 24 | basic | ❌ | ❌ | +| Font size 36 | basic | ❌ | ❌ | +| Font - Arial | basic | ❌ | ❌ | +| Font - Times New Roman | basic | ❌ | ❌ | +| Font - Courier New | basic | ❌ | ❌ | +| Font color - red | basic | ❌ | ❌ | +| Font color - blue | basic | ❌ | ❌ | +| Font color - green | basic | ❌ | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | ❌ | + +**python-calamine** — Read: 🔴 0 + +| Test | Importance | Read | +|------|-----------|------| +| Bold | basic | ❌ | +| Italic | basic | ❌ | +| Underline - single | basic | ❌ | +| Underline - double | basic | ❌ | +| Strikethrough | basic | ❌ | +| Bold + Italic | basic | ❌ | +| Font size 8 | basic | ❌ | +| Font size 14 | basic | ❌ | +| Font size 24 | basic | ❌ | +| Font size 36 | basic | ❌ | +| Font - Arial | basic | ❌ | +| Font - Times New Roman | basic | ❌ | +| Font - Courier New | basic | ❌ | +| Font color - red | basic | ❌ | +| Font color - blue | basic | ❌ | +| Font color - green | basic | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | + +**tablib** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Bold | basic | ❌ | ❌ | +| Italic | basic | ❌ | ❌ | +| Underline - single | basic | ❌ | ❌ | +| Underline - double | basic | ❌ | ❌ | +| Strikethrough | basic | ❌ | ❌ | +| Bold + Italic | basic | ❌ | ❌ | +| Font size 8 | basic | ❌ | ❌ | +| Font size 14 | basic | ❌ | ❌ | +| Font size 24 | basic | ❌ | ❌ | +| Font size 36 | basic | ❌ | ❌ | +| Font - Arial | basic | ❌ | ❌ | +| Font - Times New Roman | basic | ❌ | ❌ | +| Font - Courier New | basic | ❌ | ❌ | +| Font color - red | basic | ❌ | ❌ | +| Font color - blue | basic | ❌ | ❌ | +| Font color - green | basic | ❌ | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | ❌ | +| Combined - bold, 16pt, red | basic | ❌ | ❌ | + +**wolfxl** — Read: 🟢 3 | Write: 🟢 3 + +**xlrd** +- Notes: Not applicable: xlrd does not support .xlsx input + +**xlsxwriter** — Write: 🟢 3 + +**xlsxwriter-constmem** — Write: 🟢 3 + +**xlwt** — Write: 🟠 1 + +| Test | Importance | Write | +|------|-----------|-------| +| Bold | basic | ✅ | +| Italic | basic | ✅ | +| Underline - single | basic | ✅ | +| Underline - double | basic | ✅ | +| Strikethrough | basic | ✅ | +| Bold + Italic | basic | ✅ | +| Font size 8 | basic | ✅ | +| Font size 14 | basic | ✅ | +| Font size 24 | basic | ✅ | +| Font size 36 | basic | ✅ | +| Font - Arial | basic | ✅ | +| Font - Times New Roman | basic | ✅ | +| Font - Courier New | basic | ✅ | +| Font color - red | basic | ✅ | +| Font color - blue | basic | ✅ | +| Font color - green | basic | ❌ | +| Font color - custom (#8B4513) | basic | ❌ | +| Combined - bold, 16pt, red | basic | ✅ | + +--- +*Benchmark version: 0.1.0* \ No newline at end of file diff --git a/results-2026-09-08/xlsx/WHY_FAILED.md b/results-2026-09-08/xlsx/WHY_FAILED.md new file mode 100644 index 0000000..9cbfa87 --- /dev/null +++ b/results-2026-09-08/xlsx/WHY_FAILED.md @@ -0,0 +1,8497 @@ +# Why Failed + +## cell_values / python-calamine / read / error_div0 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / python-calamine / read / error_na + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / python-calamine / read / error_value + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / aspose-cells-foss / read / date_standard + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / aspose-cells-foss / read / datetime + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / pylightxl / write / string_simple + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / string_unicode + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / string_empty + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / string_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / string_newline + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / number_integer + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / number_float + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / number_negative + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / number_large + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / number_scientific + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / date_standard + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / datetime + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / boolean_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / boolean_false + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / error_div0 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / error_na + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / error_value + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pylightxl / write / blank + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / string_simple + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / string_unicode + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / string_empty + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / string_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / string_newline + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / number_integer + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / number_float + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / number_negative + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / number_large + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / number_scientific + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / date_standard + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / datetime + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / boolean_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / boolean_false + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / error_div0 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / error_na + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / error_value + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pyexcel / write / blank + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## cell_values / pandas / read / error_div0 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / pandas / read / error_na + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / pandas / read / error_value + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / polars / read / error_div0 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / polars / read / error_na + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## cell_values / polars / read / error_value + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## formulas / python-calamine / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / python-calamine / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / python-calamine / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / python-calamine / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pylightxl / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pylightxl / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pylightxl / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pylightxl / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pyexcel / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pyexcel / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pyexcel / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pyexcel / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / xlwt / write / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / xlwt / write / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / xlwt / write / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / xlwt / write / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pandas / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pandas / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pandas / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / pandas / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / polars / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / polars / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / polars / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / polars / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / tablib / read / formula_sum + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / tablib / read / formula_cell_ref + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / tablib / read / formula_concat + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## formulas / tablib / read / formula_cross_sheet + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## text_formatting / python-calamine / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / python-calamine / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / python-calamine / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / aspose-cells-foss / read / underline_double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / aspose-cells-foss / write / bold + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / underline_single + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / underline_double + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / strikethrough + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / bold_italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_size_8 + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_size_14 + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_size_24 + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_size_36 + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_arial + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_times + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / font_courier + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / color_green + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / aspose-cells-foss / write / combined + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss supports only a single underline, not accounting or double variants. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pylightxl / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pylightxl / write / bold + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / underline_single + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / underline_double + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / strikethrough + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / bold_italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_size_8 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_size_14 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_size_24 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_size_36 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_arial + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_times + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / font_courier + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / color_green + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pylightxl / write / combined + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pyexcel / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pyexcel / write / bold + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / underline_single + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / underline_double + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / strikethrough + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / bold_italic + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_size_8 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_size_14 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_size_24 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_size_36 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_arial + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_times + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / font_courier + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / color_green + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / pyexcel / write / combined + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## text_formatting / xlwt / write / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / xlwt / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / pandas / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / bold + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / italic + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / underline_single + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / underline_double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / strikethrough + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / bold_italic + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / pandas / write / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / openpyxl-readonly / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / openpyxl-readonly / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / polars / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / polars / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / bold + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / underline_single + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / underline_double + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / strikethrough + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / bold_italic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## text_formatting / tablib / read / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / read / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / bold + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / italic + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / underline_single + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / underline_double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / strikethrough + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / bold_italic + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_size_8 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_size_14 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_size_24 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_size_36 + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_arial + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_times + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / font_courier + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / color_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## text_formatting / tablib / write / combined + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / python-calamine / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / python-calamine / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / python-calamine / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / python-calamine / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pylightxl / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pylightxl / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pylightxl / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pylightxl / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pylightxl / write / bg_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pylightxl / write / bg_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pylightxl / write / bg_green + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pylightxl / write / bg_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pyexcel / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pyexcel / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pyexcel / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pyexcel / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pyexcel / write / bg_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pyexcel / write / bg_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pyexcel / write / bg_green + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / pyexcel / write / bg_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## background_colors / xlwt / write / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / xlwt / write / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / write / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / write / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / write / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / pandas / write / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / openpyxl-readonly / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / openpyxl-readonly / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / openpyxl-readonly / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / openpyxl-readonly / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / polars / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / polars / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / polars / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / polars / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / read / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / read / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / read / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / read / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / write / bg_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / write / bg_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / write / bg_green + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## background_colors / tablib / write / bg_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / python-calamine / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / python-calamine / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / python-calamine / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / python-calamine / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / python-calamine / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pylightxl / write / numfmt_currency + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pylightxl / write / numfmt_percent + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pylightxl / write / numfmt_date + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pylightxl / write / numfmt_scientific + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pylightxl / write / numfmt_custom_text + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pyexcel / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pyexcel / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pyexcel / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pyexcel / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pyexcel / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pyexcel / write / numfmt_currency + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pyexcel / write / numfmt_percent + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pyexcel / write / numfmt_date + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pyexcel / write / numfmt_scientific + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pyexcel / write / numfmt_custom_text + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## number_formats / pandas / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / write / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / write / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / write / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / write / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / pandas / write / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / openpyxl-readonly / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / openpyxl-readonly / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / openpyxl-readonly / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / openpyxl-readonly / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / openpyxl-readonly / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / polars / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / polars / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / polars / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / polars / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / polars / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / read / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / read / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / read / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / read / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / read / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / write / numfmt_currency + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / write / numfmt_percent + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / write / numfmt_date + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / write / numfmt_scientific + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## number_formats / tablib / write / numfmt_custom_text + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## alignment / xlsxwriter / write / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / python-calamine / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / aspose-cells-foss / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / aspose-cells-foss / write / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pylightxl / read / h_left + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / h_center + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / h_right + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / v_top + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / v_center + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / v_bottom + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / wrap_text + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / rotation_45 + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / read / indent_2 + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## alignment / pylightxl / write / h_left + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / h_center + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / h_right + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / v_top + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / v_center + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / v_bottom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / wrap_text + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / rotation_45 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pylightxl / write / indent_2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pyexcel / write / h_left + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / h_center + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / h_right + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / v_top + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / v_center + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / v_bottom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / wrap_text + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / rotation_45 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pyexcel / write / indent_2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## alignment / pandas / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / pandas / write / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / xlsxwriter-constmem / write / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / openpyxl-readonly / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / polars / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / read / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / h_left + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / h_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / h_right + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / v_top + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / v_center + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / v_bottom + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / wrap_text + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / rotation_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## alignment / tablib / write / indent_2 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / python-calamine / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / python-calamine / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / aspose-cells-foss / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / aspose-cells-foss / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / aspose-cells-foss / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / aspose-cells-foss / write / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / aspose-cells-foss / write / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / aspose-cells-foss / write / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pylightxl / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / top_only + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / bottom_only + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / left_only + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / right_only + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / diagonal_up + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / diagonal_down + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / diagonal_both + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / read / mixed_styles + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## borders / pylightxl / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pylightxl / write / thin_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / medium_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / thick_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / double + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / dashed + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / dotted + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / dash_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / dash_dot_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / top_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / bottom_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / left_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / right_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / diagonal_up + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / diagonal_down + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / diagonal_both + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / mixed_styles + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pylightxl / write / mixed_colors + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pyexcel / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pyexcel / write / thin_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / medium_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / thick_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / double + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / dashed + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / dotted + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / dash_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / dash_dot_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / top_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / bottom_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / left_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / right_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / diagonal_up + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / diagonal_down + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / diagonal_both + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / mixed_styles + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / pyexcel / write / mixed_colors + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel exposes value-only cells +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / xlwt / write / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / xlwt / write / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / xlwt / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / xlwt / write / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / pandas / write / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / pandas / write / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / openpyxl-readonly / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / openpyxl-readonly / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / polars / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / polars / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / read / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / read / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / thin_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / medium_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / thick_all + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / double + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / dashed + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / dotted + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / dash_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / dash_dot_dot + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / top_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / bottom_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / left_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / right_only + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / diagonal_up + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / diagonal_down + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / diagonal_both + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / color_red + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / color_blue + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / color_custom + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## borders / tablib / write / mixed_styles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## borders / tablib / write / mixed_colors + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## dimensions / python-calamine / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / python-calamine / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / python-calamine / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / python-calamine / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / aspose-cells-foss / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / aspose-cells-foss / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pylightxl / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pylightxl / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pylightxl / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pylightxl / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pylightxl / write / row_height_30 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pylightxl / write / row_height_45 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pylightxl / write / col_width_20 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pylightxl / write / col_width_8 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pyexcel / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pyexcel / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pyexcel / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pyexcel / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pyexcel / write / row_height_30 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose row dimension writing +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pyexcel / write / row_height_45 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose row dimension writing +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pyexcel / write / col_width_20 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose row dimension writing +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / pyexcel / write / col_width_8 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose row dimension writing +- Next debug surface: treat as unsupported capability, not a semantic regression + +## dimensions / xlwt / write / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / xlwt / write / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / write / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / write / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / write / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / pandas / write / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / xlsxwriter-constmem / write / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / xlsxwriter-constmem / write / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / openpyxl-readonly / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / openpyxl-readonly / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / openpyxl-readonly / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / openpyxl-readonly / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / polars / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / polars / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / polars / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / polars / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / read / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / read / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / read / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / read / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / write / row_height_30 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / write / row_height_45 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / write / col_width_20 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## dimensions / tablib / write / col_width_8 + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## multiple_sheets / polars / read / value_beta + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## multiple_sheets / polars / read / value_gamma + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## merged_cells / python-calamine / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / python-calamine / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / python-calamine / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / python-calamine / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / pylightxl / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pylightxl / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pylightxl / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pylightxl / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / pylightxl / write / merge_horizontal + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pylightxl / write / merge_vertical + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pylightxl / write / merge_value_off_top_left + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pylightxl / write / merge_top_left_fill + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pyexcel / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pyexcel / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pyexcel / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pyexcel / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / pyexcel / write / merge_horizontal + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pyexcel / write / merge_vertical + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pyexcel / write / merge_value_off_top_left + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / pyexcel / write / merge_top_left_fill + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## merged_cells / xlwt / write / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / xlwt / write / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / xlwt / write / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / xlwt / write / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / pandas / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / pandas / write / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / write / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / write / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / pandas / write / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / openpyxl-readonly / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / openpyxl-readonly / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / openpyxl-readonly / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / openpyxl-readonly / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / polars / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / polars / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / polars / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / polars / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / tablib / read / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / read / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / read / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / read / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## merged_cells / tablib / write / merge_horizontal + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / write / merge_vertical + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / write / merge_value_off_top_left + +- What failed: merged-cell metadata changed +- Likely cause: merged range XML or non-anchor cell handling differs +- Next debug surface: inspect mergeCells in the worksheet XML and subordinate cell behavior + +## merged_cells / tablib / write / merge_top_left_fill + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / python-calamine / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / python-calamine / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / python-calamine / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / python-calamine / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / python-calamine / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / python-calamine / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / wolfxl / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / wolfxl / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / wolfxl / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / wolfxl / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / read / cf_data_bar + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## conditional_formatting / pylightxl / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pylightxl / write / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pylightxl / write / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pylightxl / write / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pylightxl / write / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pylightxl / write / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pylightxl / write / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pyexcel / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pyexcel / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pyexcel / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / pyexcel / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pyexcel / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pyexcel / write / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / write / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / write / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / write / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / write / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pyexcel / write / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / xlwt / write / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author conditional formatting +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / pandas / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / pandas / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / write / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / write / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / write / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / write / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / pandas / write / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / pandas / write / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / openpyxl-readonly / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / openpyxl-readonly / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / openpyxl-readonly / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / openpyxl-readonly / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / openpyxl-readonly / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / openpyxl-readonly / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / polars / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / polars / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / polars / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / polars / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / polars / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / polars / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / read / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / read / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / read / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / read / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / tablib / read / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / read / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / write / cf_cell_gt + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / write / cf_formula_cross_sheet + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / write / cf_text_contains + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / write / cf_data_bar + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## conditional_formatting / tablib / write / cf_color_scale + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## conditional_formatting / tablib / write / cf_stop_if_true + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## data_validation / python-calamine / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / python-calamine / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / python-calamine / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / python-calamine / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / python-calamine / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pylightxl / write / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pylightxl / write / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pylightxl / write / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pylightxl / write / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pylightxl / write / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pyexcel / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pyexcel / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pyexcel / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pyexcel / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pyexcel / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pyexcel / write / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pyexcel / write / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pyexcel / write / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pyexcel / write / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pyexcel / write / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / xlwt / write / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author data validations +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / xlwt / write / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author data validations +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / xlwt / write / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author data validations +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / xlwt / write / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author data validations +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / xlwt / write / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author data validations +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / pandas / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / write / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / write / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / write / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / write / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / pandas / write / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / openpyxl-readonly / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / openpyxl-readonly / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / openpyxl-readonly / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / openpyxl-readonly / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / openpyxl-readonly / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / polars / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / polars / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / polars / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / polars / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / polars / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / read / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / read / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / read / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / read / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / read / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / write / dv_list_csv + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / write / dv_list_range + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / write / dv_cross_sheet + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / write / dv_custom_formula + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## data_validation / tablib / write / dv_whole_between + +- What failed: data validation metadata changed +- Likely cause: validation type, formula, or target range was dropped or rewritten +- Next debug surface: inspect dataValidations in the worksheet XML + +## hyperlinks / python-calamine / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / python-calamine / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / python-calamine / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / python-calamine / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / aspose-cells-foss / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / aspose-cells-foss / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / aspose-cells-foss / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / aspose-cells-foss / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pylightxl / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pylightxl / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pylightxl / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pylightxl / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pylightxl / write / link_external + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pylightxl / write / link_internal + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pylightxl / write / link_mailto + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pylightxl / write / link_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pyexcel / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pyexcel / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pyexcel / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pyexcel / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pyexcel / write / link_external + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pyexcel / write / link_internal + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pyexcel / write / link_mailto + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pyexcel / write / link_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / xlwt / write / link_external + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt hyperlink metadata is not supported in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / xlwt / write / link_internal + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt hyperlink metadata is not supported in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / xlwt / write / link_mailto + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt hyperlink metadata is not supported in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / xlwt / write / link_long + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt hyperlink metadata is not supported in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## hyperlinks / pandas / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / write / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / write / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / write / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / pandas / write / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / openpyxl-readonly / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / openpyxl-readonly / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / openpyxl-readonly / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / openpyxl-readonly / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / polars / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / polars / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / polars / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / polars / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / read / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / read / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / read / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / read / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / write / link_external + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / write / link_internal + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / write / link_mailto + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## hyperlinks / tablib / write / link_long + +- What failed: hyperlink target or display metadata changed +- Likely cause: hyperlink rel target, tooltip, or internal location was not preserved +- Next debug surface: inspect worksheet hyperlinks and worksheet rels + +## images / python-calamine / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / python-calamine / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / aspose-cells-foss / read / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / aspose-cells-foss / read / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / aspose-cells-foss / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / aspose-cells-foss / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / pylightxl / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pylightxl / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pylightxl / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / pylightxl / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / pyexcel / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pyexcel / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pyexcel / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / pyexcel / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / xlwt / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot embed images in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / xlwt / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot embed images in this adapter +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / pandas / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pandas / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pandas / write / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / pandas / write / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / xlsxwriter-constmem / write / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / xlsxwriter-constmem / write / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / openpyxl-readonly / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / openpyxl-readonly / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / polars / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / polars / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / tablib / read / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / tablib / read / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / tablib / write / image_one_cell + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## images / tablib / write / image_two_cell_offset + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## comments / python-calamine / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / python-calamine / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / python-calamine / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / aspose-cells-foss / write / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / aspose-cells-foss / write / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / aspose-cells-foss / write / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pylightxl / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pylightxl / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pylightxl / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pylightxl / write / comment_legacy + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pylightxl / write / comment_threaded + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pylightxl / write / comment_author + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pyexcel / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pyexcel / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pyexcel / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pyexcel / write / comment_legacy + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pyexcel / write / comment_threaded + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pyexcel / write / comment_author + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / xlwt / write / comment_legacy + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author comments +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / xlwt / write / comment_threaded + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author comments +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / xlwt / write / comment_author + +- What failed: adapter reported this operation as unsupported +- Likely cause: xlwt cannot author comments +- Next debug surface: treat as unsupported capability, not a semantic regression + +## comments / pandas / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pandas / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pandas / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pandas / write / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pandas / write / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / pandas / write / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / xlsxwriter-constmem / write / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / xlsxwriter-constmem / write / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / xlsxwriter-constmem / write / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / openpyxl-readonly / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / openpyxl-readonly / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / openpyxl-readonly / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / polars / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / polars / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / polars / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / read / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / read / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / read / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / write / comment_legacy + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / write / comment_threaded + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## comments / tablib / write / comment_author + +- What failed: comment metadata changed +- Likely cause: legacy comment text, author, or VML relationship was not preserved +- Next debug surface: inspect comments XML plus VML drawing relationships + +## freeze_panes / python-calamine / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / python-calamine / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / python-calamine / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pylightxl / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pylightxl / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pylightxl / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pylightxl / write / freeze_b2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / pylightxl / write / freeze_d5 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / pylightxl / write / split_2x1 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pylightxl does not implement this feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / pyexcel / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pyexcel / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pyexcel / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pyexcel / write / freeze_b2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / pyexcel / write / freeze_d5 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / pyexcel / write / split_2x1 + +- What failed: adapter reported this operation as unsupported +- Likely cause: pyexcel does not expose this worksheet feature +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / xlwt / write / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / xlwt / write / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / xlwt / write / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / write / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / write / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / pandas / write / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / openpyxl-readonly / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / openpyxl-readonly / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / openpyxl-readonly / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / polars / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / polars / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / polars / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / read / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / read / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / read / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / write / freeze_b2 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / write / freeze_d5 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## freeze_panes / tablib / write / split_2x1 + +- What failed: freeze pane settings changed +- Likely cause: pane split/top-left metadata was dropped or normalized incorrectly +- Next debug surface: inspect sheetViews/pane in the worksheet XML + +## named_ranges / xlsxwriter / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / python-calamine / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / aspose-cells-foss / read / nr_sheet_scope + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / wolfxl / write / nr_sheet_scope + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_simple_cell + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_cell_range + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_formula_ref + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_sheet_scope + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_cross_sheet + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / read / nr_special_chars + +- What failed: named range metadata changed +- Likely cause: workbook-level vs sheet-level defined-name scope was lost or rewritten +- Next debug surface: inspect workbook.xml definedNames and localSheetId values + +## named_ranges / pylightxl / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pylightxl / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pylightxl / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pylightxl / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pylightxl / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pylightxl / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pyexcel / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlwt / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / pandas / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / xlsxwriter-constmem / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / openpyxl-readonly / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / polars / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / read / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_simple_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_cell_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_formula_ref + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_sheet_scope + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## named_ranges / tablib / write / nr_special_chars + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / python-calamine / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / aspose-cells-foss / read / tbl_with_totals + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / aspose-cells-foss / read / tbl_no_style + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / aspose-cells-foss / write / tbl_with_totals + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / aspose-cells-foss / write / tbl_no_style + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_basic + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_with_totals + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_no_style + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_single_col + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_single_row + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / read / tbl_autofilter + +- What failed: cell style metadata changed +- Likely cause: formatting was dropped, defaulted, or normalized differently +- Next debug surface: inspect styles.xml and the adapter's style mapping + +## tables / pylightxl / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pylightxl / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pylightxl / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pylightxl / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pylightxl / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pylightxl / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pyexcel / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlwt / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / pandas / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / xlsxwriter-constmem / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / openpyxl-readonly / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / polars / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / tablib / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / python-calamine / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / python-calamine / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / python-calamine / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pylightxl / read / prot_basic + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## sheet_protection / pylightxl / read / prot_password + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## sheet_protection / pylightxl / read / prot_granular + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## sheet_protection / pylightxl / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pylightxl / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pylightxl / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pyexcel / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlwt / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlwt / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlwt / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / pandas / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter-constmem / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter-constmem / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / xlsxwriter-constmem / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / openpyxl-readonly / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / openpyxl-readonly / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / openpyxl-readonly / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / polars / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / polars / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / polars / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / write / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / write / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / tablib / write / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / python-calamine / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / python-calamine / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / python-calamine / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / aspose-cells-foss / read / page_setup_landscape + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## page_setup / aspose-cells-foss / read / page_setup_titles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## page_setup / aspose-cells-foss / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss has no print-title-rows API. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / aspose-cells-foss / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss has no print-title-rows API. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / aspose-cells-foss / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: aspose-cells-foss has no print-title-rows API. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / wolfxl / write / page_setup_titles + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## page_setup / pylightxl / read / page_setup_landscape + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## page_setup / pylightxl / read / page_setup_scale + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## page_setup / pylightxl / read / page_setup_titles + +- What failed: adapter raised instead of returning comparable workbook data +- Likely cause: adapter/runtime error interrupted the assertion path +- Next debug surface: open the diagnostic adapter message and reproduce the adapter call directly + +## page_setup / pylightxl / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pylightxl / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pylightxl / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pyexcel / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlwt / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlwt / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlwt / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / pandas / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter-constmem / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter-constmem / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / xlsxwriter-constmem / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / openpyxl-readonly / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / openpyxl-readonly / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / openpyxl-readonly / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / polars / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / polars / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / polars / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / read / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / read / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / read / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / write / page_setup_landscape + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / write / page_setup_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## page_setup / tablib / write / page_setup_titles + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlsxwriter / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlsxwriter / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / python-calamine / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / python-calamine / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pylightxl / read / chart_bar + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## chart_anchor / pylightxl / read / chart_line + +- What failed: image or drawing relationship changed +- Likely cause: media part may exist but worksheet drawing rels or anchors do not match +- Next debug surface: inspect drawing XML, drawing rels, and xl/media package parts + +## chart_anchor / pylightxl / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pylightxl / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pyexcel / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pyexcel / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pyexcel / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pyexcel / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlwt / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlwt / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pandas / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pandas / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pandas / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / pandas / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlsxwriter-constmem / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / xlsxwriter-constmem / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / openpyxl-readonly / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / openpyxl-readonly / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / polars / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / polars / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / tablib / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / tablib / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter raised an exception while evaluating this test case. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / tablib / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / tablib / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: Adapter could not create or save a workbook for this feature. +- Next debug surface: treat as unsupported capability, not a semantic regression diff --git a/results-2026-09-08/xlsx/heatmap.png b/results-2026-09-08/xlsx/heatmap.png new file mode 100644 index 0000000..4f7690e Binary files /dev/null and b/results-2026-09-08/xlsx/heatmap.png differ diff --git a/results-2026-09-08/xlsx/heatmap.svg b/results-2026-09-08/xlsx/heatmap.svg new file mode 100644 index 0000000..7f94e65 --- /dev/null +++ b/results-2026-09-08/xlsx/heatmap.svg @@ -0,0 +1,4174 @@ + + + + + + + + 2026-09-07T22:48:38.385380 + image/svg+xml + + + Matplotlib v3.10.8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/results-2026-09-08/xlsx/history.jsonl b/results-2026-09-08/xlsx/history.jsonl new file mode 100644 index 0000000..a5ab36c --- /dev/null +++ b/results-2026-09-08/xlsx/history.jsonl @@ -0,0 +1 @@ +{"run_date": "2026-09-08T05:35:34.204256+00:00", "commit": "9a0b300", "profile": "xlsx", "scores": {"openpyxl": {"cell_values": {"read": 3, "write": 3}, "formulas": {"read": 3, "write": 3}, "text_formatting": {"read": 3, "write": 3}, "background_colors": {"read": 3, "write": 3}, "number_formats": {"read": 3, "write": 3}, "alignment": {"read": 3, "write": 3}, "borders": {"read": 3, "write": 3}, "dimensions": {"read": 3, "write": 3}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 3, "write": 3}, "conditional_formatting": {"read": 3, "write": 3}, "data_validation": {"read": 3, "write": 3}, "hyperlinks": {"read": 3, "write": 3}, "images": {"read": 3, "write": 3}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 3}, "freeze_panes": {"read": 3, "write": 3}, "named_ranges": {"read": 3, "write": 3}, "tables": {"read": 3, "write": 3}, "sheet_protection": {"read": 3, "write": 3}, "page_setup": {"read": 3, "write": 3}, "chart_anchor": {"read": 3, "write": 3}}, "xlsxwriter": {"cell_values": {"read": null, "write": 3}, "formulas": {"read": null, "write": 3}, "text_formatting": {"read": null, "write": 3}, "background_colors": {"read": null, "write": 3}, "number_formats": {"read": null, "write": 3}, "alignment": {"read": null, "write": 1}, "borders": {"read": null, "write": 3}, "dimensions": {"read": null, "write": 3}, "multiple_sheets": {"read": null, "write": 3}, "merged_cells": {"read": null, "write": 3}, "conditional_formatting": {"read": null, "write": 3}, "data_validation": {"read": null, "write": 3}, "hyperlinks": {"read": null, "write": 3}, "images": {"read": null, "write": 3}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": null, "write": 3}, "freeze_panes": {"read": null, "write": 3}, "named_ranges": {"read": null, "write": 0}, "tables": {"read": null, "write": 0}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}, "python-calamine": {"cell_values": {"read": 1, "write": null}, "formulas": {"read": 0, "write": null}, "text_formatting": {"read": 0, "write": null}, "background_colors": {"read": 0, "write": null}, "number_formats": {"read": 0, "write": null}, "alignment": {"read": 0, "write": null}, "borders": {"read": 0, "write": null}, "dimensions": {"read": 0, "write": null}, "multiple_sheets": {"read": 3, "write": null}, "merged_cells": {"read": 0, "write": null}, "conditional_formatting": {"read": 0, "write": null}, "data_validation": {"read": 0, "write": null}, "hyperlinks": {"read": 0, "write": null}, "images": {"read": 0, "write": null}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": null}, "freeze_panes": {"read": 0, "write": null}, "named_ranges": {"read": 0, "write": null}, "tables": {"read": 0, "write": null}, "sheet_protection": {"read": 0, "write": null}, "page_setup": {"read": 0, "write": null}, "chart_anchor": {"read": 0, "write": null}}, "aspose-cells-foss": {"cell_values": {"read": 1, "write": 3}, "formulas": {"read": 3, "write": 3}, "text_formatting": {"read": 1, "write": 0}, "background_colors": {"read": 3, "write": 3}, "number_formats": {"read": 3, "write": 3}, "alignment": {"read": 1, "write": 1}, "borders": {"read": 1, "write": 1}, "dimensions": {"read": 1, "write": 3}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 3, "write": 3}, "conditional_formatting": {"read": 3, "write": 3}, "data_validation": {"read": 3, "write": 3}, "hyperlinks": {"read": 0, "write": 3}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 0}, "freeze_panes": {"read": 3, "write": 3}, "named_ranges": {"read": 2, "write": 3}, "tables": {"read": 1, "write": 1}, "sheet_protection": {"read": 3, "write": 3}, "page_setup": {"read": 1, "write": 0}, "chart_anchor": {"read": 3, "write": 3}}, "wolfxl": {"cell_values": {"read": 3, "write": 3}, "formulas": {"read": 3, "write": 3}, "text_formatting": {"read": 3, "write": 3}, "background_colors": {"read": 3, "write": 3}, "number_formats": {"read": 3, "write": 3}, "alignment": {"read": 3, "write": 3}, "borders": {"read": 3, "write": 3}, "dimensions": {"read": 3, "write": 3}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 3, "write": 3}, "conditional_formatting": {"read": 0, "write": 3}, "data_validation": {"read": 3, "write": 3}, "hyperlinks": {"read": 3, "write": 3}, "images": {"read": 3, "write": 3}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 3}, "freeze_panes": {"read": 3, "write": 3}, "named_ranges": {"read": 3, "write": 2}, "tables": {"read": 3, "write": 3}, "sheet_protection": {"read": 3, "write": 3}, "page_setup": {"read": 3, "write": 2}, "chart_anchor": {"read": 3, "write": 3}}, "pylightxl": {"cell_values": {"read": 3, "write": 0}, "formulas": {"read": 0, "write": 3}, "text_formatting": {"read": 0, "write": 0}, "background_colors": {"read": 0, "write": 0}, "number_formats": {"read": 0, "write": 0}, "alignment": {"read": 0, "write": 0}, "borders": {"read": 0, "write": 0}, "dimensions": {"read": 0, "write": 0}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 0, "write": 0}, "conditional_formatting": {"read": 0, "write": 0}, "data_validation": {"read": 0, "write": 0}, "hyperlinks": {"read": 0, "write": 0}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": 0}, "freeze_panes": {"read": 0, "write": 0}, "named_ranges": {"read": 0, "write": 0}, "tables": {"read": 0, "write": 0}, "sheet_protection": {"read": 0, "write": 0}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}, "xlrd": {"cell_values": {"read": null, "write": null}, "formulas": {"read": null, "write": null}, "text_formatting": {"read": null, "write": null}, "background_colors": {"read": null, "write": null}, "number_formats": {"read": null, "write": null}, "alignment": {"read": null, "write": null}, "borders": {"read": null, "write": null}, "dimensions": {"read": null, "write": null}, "multiple_sheets": {"read": null, "write": null}, "merged_cells": {"read": null, "write": null}, "conditional_formatting": {"read": null, "write": null}, "data_validation": {"read": null, "write": null}, "hyperlinks": {"read": null, "write": null}, "images": {"read": null, "write": null}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": null, "write": null}, "freeze_panes": {"read": null, "write": null}, "named_ranges": {"read": null, "write": null}, "tables": {"read": null, "write": null}, "sheet_protection": {"read": null, "write": null}, "page_setup": {"read": null, "write": null}, "chart_anchor": {"read": null, "write": null}}, "pyexcel": {"cell_values": {"read": 3, "write": 0}, "formulas": {"read": 0, "write": 3}, "text_formatting": {"read": 0, "write": 0}, "background_colors": {"read": 0, "write": 0}, "number_formats": {"read": 0, "write": 0}, "alignment": {"read": 0, "write": 0}, "borders": {"read": 0, "write": 0}, "dimensions": {"read": 0, "write": 0}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 0, "write": 0}, "conditional_formatting": {"read": 0, "write": 0}, "data_validation": {"read": 0, "write": 0}, "hyperlinks": {"read": 0, "write": 0}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": 0}, "freeze_panes": {"read": 0, "write": 0}, "named_ranges": {"read": 0, "write": 0}, "tables": {"read": 0, "write": 0}, "sheet_protection": {"read": 0, "write": 0}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}, "xlwt": {"cell_values": {"read": null, "write": 3}, "formulas": {"read": null, "write": 0}, "text_formatting": {"read": null, "write": 1}, "background_colors": {"read": null, "write": 1}, "number_formats": {"read": null, "write": 3}, "alignment": {"read": null, "write": 3}, "borders": {"read": null, "write": 1}, "dimensions": {"read": null, "write": 1}, "multiple_sheets": {"read": null, "write": 3}, "merged_cells": {"read": null, "write": 0}, "conditional_formatting": {"read": null, "write": 0}, "data_validation": {"read": null, "write": 0}, "hyperlinks": {"read": null, "write": 0}, "images": {"read": null, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": null, "write": 0}, "freeze_panes": {"read": null, "write": 0}, "named_ranges": {"read": null, "write": 0}, "tables": {"read": null, "write": 0}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}, "pandas": {"cell_values": {"read": 1, "write": 3}, "formulas": {"read": 0, "write": 3}, "text_formatting": {"read": 0, "write": 0}, "background_colors": {"read": 0, "write": 0}, "number_formats": {"read": 0, "write": 0}, "alignment": {"read": 0, "write": 0}, "borders": {"read": 0, "write": 0}, "dimensions": {"read": 0, "write": 0}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 0, "write": 0}, "conditional_formatting": {"read": 0, "write": 0}, "data_validation": {"read": 0, "write": 0}, "hyperlinks": {"read": 0, "write": 0}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": 0}, "freeze_panes": {"read": 0, "write": 0}, "named_ranges": {"read": 0, "write": 0}, "tables": {"read": 0, "write": 0}, "sheet_protection": {"read": 0, "write": 0}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}, "xlsxwriter-constmem": {"cell_values": {"read": null, "write": 3}, "formulas": {"read": null, "write": 3}, "text_formatting": {"read": null, "write": 3}, "background_colors": {"read": null, "write": 3}, "number_formats": {"read": null, "write": 3}, "alignment": {"read": null, "write": 1}, "borders": {"read": null, "write": 3}, "dimensions": {"read": null, "write": 1}, "multiple_sheets": {"read": null, "write": 3}, "merged_cells": {"read": null, "write": 3}, "conditional_formatting": {"read": null, "write": 3}, "data_validation": {"read": null, "write": 3}, "hyperlinks": {"read": null, "write": 3}, "images": {"read": null, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": null, "write": 0}, "freeze_panes": {"read": null, "write": 3}, "named_ranges": {"read": null, "write": 0}, "tables": {"read": null, "write": 0}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}, "openpyxl-readonly": {"cell_values": {"read": 3, "write": null}, "formulas": {"read": 3, "write": null}, "text_formatting": {"read": 0, "write": null}, "background_colors": {"read": 0, "write": null}, "number_formats": {"read": 0, "write": null}, "alignment": {"read": 0, "write": null}, "borders": {"read": 0, "write": null}, "dimensions": {"read": 0, "write": null}, "multiple_sheets": {"read": 3, "write": null}, "merged_cells": {"read": 0, "write": null}, "conditional_formatting": {"read": 0, "write": null}, "data_validation": {"read": 0, "write": null}, "hyperlinks": {"read": 0, "write": null}, "images": {"read": 0, "write": null}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": null}, "freeze_panes": {"read": 0, "write": null}, "named_ranges": {"read": 0, "write": null}, "tables": {"read": 0, "write": null}, "sheet_protection": {"read": 0, "write": null}, "page_setup": {"read": 0, "write": null}, "chart_anchor": {"read": 0, "write": null}}, "polars": {"cell_values": {"read": 1, "write": null}, "formulas": {"read": 0, "write": null}, "text_formatting": {"read": 0, "write": null}, "background_colors": {"read": 0, "write": null}, "number_formats": {"read": 0, "write": null}, "alignment": {"read": 0, "write": null}, "borders": {"read": 0, "write": null}, "dimensions": {"read": 0, "write": null}, "multiple_sheets": {"read": 1, "write": null}, "merged_cells": {"read": 0, "write": null}, "conditional_formatting": {"read": 0, "write": null}, "data_validation": {"read": 0, "write": null}, "hyperlinks": {"read": 0, "write": null}, "images": {"read": 0, "write": null}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": null}, "freeze_panes": {"read": 0, "write": null}, "named_ranges": {"read": 0, "write": null}, "tables": {"read": 0, "write": null}, "sheet_protection": {"read": 0, "write": null}, "page_setup": {"read": 0, "write": null}, "chart_anchor": {"read": 0, "write": null}}, "tablib": {"cell_values": {"read": 3, "write": 3}, "formulas": {"read": 0, "write": 3}, "text_formatting": {"read": 0, "write": 0}, "background_colors": {"read": 0, "write": 0}, "number_formats": {"read": 0, "write": 0}, "alignment": {"read": 0, "write": 0}, "borders": {"read": 0, "write": 0}, "dimensions": {"read": 0, "write": 0}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 0, "write": 0}, "conditional_formatting": {"read": 0, "write": 0}, "data_validation": {"read": 0, "write": 0}, "hyperlinks": {"read": 0, "write": 0}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 0, "write": 0}, "freeze_panes": {"read": 0, "write": 0}, "named_ranges": {"read": 0, "write": 0}, "tables": {"read": 0, "write": 0}, "sheet_protection": {"read": 0, "write": 0}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}}} diff --git a/results-2026-09-08/xlsx/matrix.csv b/results-2026-09-08/xlsx/matrix.csv new file mode 100644 index 0000000..99fa462 --- /dev/null +++ b/results-2026-09-08/xlsx/matrix.csv @@ -0,0 +1,309 @@ +library,feature,read_score,write_score +openpyxl,cell_values,3,3 +xlsxwriter,cell_values,,3 +python-calamine,cell_values,1, +aspose-cells-foss,cell_values,1,3 +wolfxl,cell_values,3,3 +pylightxl,cell_values,3,0 +xlrd,cell_values,, +pyexcel,cell_values,3,0 +xlwt,cell_values,,3 +pandas,cell_values,1,3 +xlsxwriter-constmem,cell_values,,3 +openpyxl-readonly,cell_values,3, +polars,cell_values,1, +tablib,cell_values,3,3 +openpyxl,formulas,3,3 +xlsxwriter,formulas,,3 +python-calamine,formulas,0, +aspose-cells-foss,formulas,3,3 +wolfxl,formulas,3,3 +pylightxl,formulas,0,3 +xlrd,formulas,, +pyexcel,formulas,0,3 +xlwt,formulas,,0 +pandas,formulas,0,3 +xlsxwriter-constmem,formulas,,3 +openpyxl-readonly,formulas,3, +polars,formulas,0, +tablib,formulas,0,3 +openpyxl,text_formatting,3,3 +xlsxwriter,text_formatting,,3 +python-calamine,text_formatting,0, +aspose-cells-foss,text_formatting,1,0 +wolfxl,text_formatting,3,3 +pylightxl,text_formatting,0,0 +xlrd,text_formatting,, +pyexcel,text_formatting,0,0 +xlwt,text_formatting,,1 +pandas,text_formatting,0,0 +xlsxwriter-constmem,text_formatting,,3 +openpyxl-readonly,text_formatting,0, +polars,text_formatting,0, +tablib,text_formatting,0,0 +openpyxl,background_colors,3,3 +xlsxwriter,background_colors,,3 +python-calamine,background_colors,0, +aspose-cells-foss,background_colors,3,3 +wolfxl,background_colors,3,3 +pylightxl,background_colors,0,0 +xlrd,background_colors,, +pyexcel,background_colors,0,0 +xlwt,background_colors,,1 +pandas,background_colors,0,0 +xlsxwriter-constmem,background_colors,,3 +openpyxl-readonly,background_colors,0, +polars,background_colors,0, +tablib,background_colors,0,0 +openpyxl,number_formats,3,3 +xlsxwriter,number_formats,,3 +python-calamine,number_formats,0, +aspose-cells-foss,number_formats,3,3 +wolfxl,number_formats,3,3 +pylightxl,number_formats,0,0 +xlrd,number_formats,, +pyexcel,number_formats,0,0 +xlwt,number_formats,,3 +pandas,number_formats,0,0 +xlsxwriter-constmem,number_formats,,3 +openpyxl-readonly,number_formats,0, +polars,number_formats,0, +tablib,number_formats,0,0 +openpyxl,alignment,3,3 +xlsxwriter,alignment,,1 +python-calamine,alignment,0, +aspose-cells-foss,alignment,1,1 +wolfxl,alignment,3,3 +pylightxl,alignment,0,0 +xlrd,alignment,, +pyexcel,alignment,0,0 +xlwt,alignment,,3 +pandas,alignment,0,0 +xlsxwriter-constmem,alignment,,1 +openpyxl-readonly,alignment,0, +polars,alignment,0, +tablib,alignment,0,0 +openpyxl,borders,3,3 +xlsxwriter,borders,,3 +python-calamine,borders,0, +aspose-cells-foss,borders,1,1 +wolfxl,borders,3,3 +pylightxl,borders,0,0 +xlrd,borders,, +pyexcel,borders,0,0 +xlwt,borders,,1 +pandas,borders,0,0 +xlsxwriter-constmem,borders,,3 +openpyxl-readonly,borders,0, +polars,borders,0, +tablib,borders,0,0 +openpyxl,dimensions,3,3 +xlsxwriter,dimensions,,3 +python-calamine,dimensions,0, +aspose-cells-foss,dimensions,1,3 +wolfxl,dimensions,3,3 +pylightxl,dimensions,0,0 +xlrd,dimensions,, +pyexcel,dimensions,0,0 +xlwt,dimensions,,1 +pandas,dimensions,0,0 +xlsxwriter-constmem,dimensions,,1 +openpyxl-readonly,dimensions,0, +polars,dimensions,0, +tablib,dimensions,0,0 +openpyxl,multiple_sheets,3,3 +xlsxwriter,multiple_sheets,,3 +python-calamine,multiple_sheets,3, +aspose-cells-foss,multiple_sheets,3,3 +wolfxl,multiple_sheets,3,3 +pylightxl,multiple_sheets,3,3 +xlrd,multiple_sheets,, +pyexcel,multiple_sheets,3,3 +xlwt,multiple_sheets,,3 +pandas,multiple_sheets,3,3 +xlsxwriter-constmem,multiple_sheets,,3 +openpyxl-readonly,multiple_sheets,3, +polars,multiple_sheets,1, +tablib,multiple_sheets,3,3 +openpyxl,merged_cells,3,3 +xlsxwriter,merged_cells,,3 +python-calamine,merged_cells,0, +aspose-cells-foss,merged_cells,3,3 +wolfxl,merged_cells,3,3 +pylightxl,merged_cells,0,0 +xlrd,merged_cells,, +pyexcel,merged_cells,0,0 +xlwt,merged_cells,,0 +pandas,merged_cells,0,0 +xlsxwriter-constmem,merged_cells,,3 +openpyxl-readonly,merged_cells,0, +polars,merged_cells,0, +tablib,merged_cells,0,0 +openpyxl,conditional_formatting,3,3 +xlsxwriter,conditional_formatting,,3 +python-calamine,conditional_formatting,0, +aspose-cells-foss,conditional_formatting,3,3 +wolfxl,conditional_formatting,0,3 +pylightxl,conditional_formatting,0,0 +xlrd,conditional_formatting,, +pyexcel,conditional_formatting,0,0 +xlwt,conditional_formatting,,0 +pandas,conditional_formatting,0,0 +xlsxwriter-constmem,conditional_formatting,,3 +openpyxl-readonly,conditional_formatting,0, +polars,conditional_formatting,0, +tablib,conditional_formatting,0,0 +openpyxl,data_validation,3,3 +xlsxwriter,data_validation,,3 +python-calamine,data_validation,0, +aspose-cells-foss,data_validation,3,3 +wolfxl,data_validation,3,3 +pylightxl,data_validation,0,0 +xlrd,data_validation,, +pyexcel,data_validation,0,0 +xlwt,data_validation,,0 +pandas,data_validation,0,0 +xlsxwriter-constmem,data_validation,,3 +openpyxl-readonly,data_validation,0, +polars,data_validation,0, +tablib,data_validation,0,0 +openpyxl,hyperlinks,3,3 +xlsxwriter,hyperlinks,,3 +python-calamine,hyperlinks,0, +aspose-cells-foss,hyperlinks,0,3 +wolfxl,hyperlinks,3,3 +pylightxl,hyperlinks,0,0 +xlrd,hyperlinks,, +pyexcel,hyperlinks,0,0 +xlwt,hyperlinks,,0 +pandas,hyperlinks,0,0 +xlsxwriter-constmem,hyperlinks,,3 +openpyxl-readonly,hyperlinks,0, +polars,hyperlinks,0, +tablib,hyperlinks,0,0 +openpyxl,images,3,3 +xlsxwriter,images,,3 +python-calamine,images,0, +aspose-cells-foss,images,0,0 +wolfxl,images,3,3 +pylightxl,images,0,0 +xlrd,images,, +pyexcel,images,0,0 +xlwt,images,,0 +pandas,images,0,0 +xlsxwriter-constmem,images,,0 +openpyxl-readonly,images,0, +polars,images,0, +tablib,images,0,0 +openpyxl,pivot_tables,, +xlsxwriter,pivot_tables,, +python-calamine,pivot_tables,, +aspose-cells-foss,pivot_tables,, +wolfxl,pivot_tables,, +pylightxl,pivot_tables,, +xlrd,pivot_tables,, +pyexcel,pivot_tables,, +xlwt,pivot_tables,, +pandas,pivot_tables,, +xlsxwriter-constmem,pivot_tables,, +openpyxl-readonly,pivot_tables,, +polars,pivot_tables,, +tablib,pivot_tables,, +openpyxl,comments,3,3 +xlsxwriter,comments,,3 +python-calamine,comments,0, +aspose-cells-foss,comments,3,0 +wolfxl,comments,3,3 +pylightxl,comments,0,0 +xlrd,comments,, +pyexcel,comments,0,0 +xlwt,comments,,0 +pandas,comments,0,0 +xlsxwriter-constmem,comments,,0 +openpyxl-readonly,comments,0, +polars,comments,0, +tablib,comments,0,0 +openpyxl,freeze_panes,3,3 +xlsxwriter,freeze_panes,,3 +python-calamine,freeze_panes,0, +aspose-cells-foss,freeze_panes,3,3 +wolfxl,freeze_panes,3,3 +pylightxl,freeze_panes,0,0 +xlrd,freeze_panes,, +pyexcel,freeze_panes,0,0 +xlwt,freeze_panes,,0 +pandas,freeze_panes,0,0 +xlsxwriter-constmem,freeze_panes,,3 +openpyxl-readonly,freeze_panes,0, +polars,freeze_panes,0, +tablib,freeze_panes,0,0 +openpyxl,named_ranges,3,3 +xlsxwriter,named_ranges,,0 +python-calamine,named_ranges,0, +aspose-cells-foss,named_ranges,2,3 +wolfxl,named_ranges,3,2 +pylightxl,named_ranges,0,0 +xlrd,named_ranges,, +pyexcel,named_ranges,0,0 +xlwt,named_ranges,,0 +pandas,named_ranges,0,0 +xlsxwriter-constmem,named_ranges,,0 +openpyxl-readonly,named_ranges,0, +polars,named_ranges,0, +tablib,named_ranges,0,0 +openpyxl,tables,3,3 +xlsxwriter,tables,,0 +python-calamine,tables,0, +aspose-cells-foss,tables,1,1 +wolfxl,tables,3,3 +pylightxl,tables,0,0 +xlrd,tables,, +pyexcel,tables,0,0 +xlwt,tables,,0 +pandas,tables,0,0 +xlsxwriter-constmem,tables,,0 +openpyxl-readonly,tables,0, +polars,tables,0, +tablib,tables,0,0 +openpyxl,sheet_protection,3,3 +xlsxwriter,sheet_protection,,0 +python-calamine,sheet_protection,0, +aspose-cells-foss,sheet_protection,3,3 +wolfxl,sheet_protection,3,3 +pylightxl,sheet_protection,0,0 +xlrd,sheet_protection,, +pyexcel,sheet_protection,0,0 +xlwt,sheet_protection,,0 +pandas,sheet_protection,0,0 +xlsxwriter-constmem,sheet_protection,,0 +openpyxl-readonly,sheet_protection,0, +polars,sheet_protection,0, +tablib,sheet_protection,0,0 +openpyxl,page_setup,3,3 +xlsxwriter,page_setup,,0 +python-calamine,page_setup,0, +aspose-cells-foss,page_setup,1,0 +wolfxl,page_setup,3,2 +pylightxl,page_setup,0,0 +xlrd,page_setup,, +pyexcel,page_setup,0,0 +xlwt,page_setup,,0 +pandas,page_setup,0,0 +xlsxwriter-constmem,page_setup,,0 +openpyxl-readonly,page_setup,0, +polars,page_setup,0, +tablib,page_setup,0,0 +openpyxl,chart_anchor,3,3 +xlsxwriter,chart_anchor,,0 +python-calamine,chart_anchor,0, +aspose-cells-foss,chart_anchor,3,3 +wolfxl,chart_anchor,3,3 +pylightxl,chart_anchor,0,0 +xlrd,chart_anchor,, +pyexcel,chart_anchor,0,0 +xlwt,chart_anchor,,0 +pandas,chart_anchor,0,0 +xlsxwriter-constmem,chart_anchor,,0 +openpyxl-readonly,chart_anchor,0, +polars,chart_anchor,0, +tablib,chart_anchor,0,0 \ No newline at end of file diff --git a/results-2026-09-08/xlsx/results.json b/results-2026-09-08/xlsx/results.json new file mode 100644 index 0000000..7ba96a6 --- /dev/null +++ b/results-2026-09-08/xlsx/results.json @@ -0,0 +1,81010 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-09-08T05:35:34.204256+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx" + }, + "libraries": { + "openpyxl": { + "name": "openpyxl", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "write", + "read" + ] + }, + "xlsxwriter": { + "name": "xlsxwriter", + "version": "3.2.9", + "language": "python", + "capabilities": [ + "write" + ] + }, + "python-calamine": { + "name": "python-calamine", + "version": "0.6.1", + "language": "python", + "capabilities": [ + "read" + ] + }, + "aspose-cells-foss": { + "name": "aspose-cells-foss", + "version": "26.7.0", + "language": "python", + "capabilities": [ + "write", + "read" + ] + }, + "wolfxl": { + "name": "wolfxl", + "version": "2.1.0", + "language": "python", + "capabilities": [ + "modify", + "write", + "read" + ] + }, + "pylightxl": { + "name": "pylightxl", + "version": "1.61", + "language": "python", + "capabilities": [ + "write", + "read" + ] + }, + "xlrd": { + "name": "xlrd", + "version": "2.0.2", + "language": "python", + "capabilities": [ + "read" + ] + }, + "pyexcel": { + "name": "pyexcel", + "version": "0.7.4", + "language": "python", + "capabilities": [ + "write", + "read" + ] + }, + "xlwt": { + "name": "xlwt", + "version": "1.3.0", + "language": "python", + "capabilities": [ + "write" + ] + }, + "pandas": { + "name": "pandas", + "version": "3.0.0", + "language": "python", + "capabilities": [ + "write", + "read" + ] + }, + "xlsxwriter-constmem": { + "name": "xlsxwriter-constmem", + "version": "3.2.9", + "language": "python", + "capabilities": [ + "write" + ] + }, + "openpyxl-readonly": { + "name": "openpyxl-readonly", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "read" + ] + }, + "polars": { + "name": "polars", + "version": "1.38.1", + "language": "python", + "capabilities": [ + "read" + ] + }, + "tablib": { + "name": "tablib", + "version": "3.9.0", + "language": "python", + "capabilities": [ + "write", + "read" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "string_simple": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "python-calamine", + "scores": { + "read": 1, + "write": null + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_div0", + "sheet": "cell_values", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_na", + "sheet": "cell_values", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_value", + "sheet": "cell_values", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": "Known limitation: python-calamine can surface formula error cells as blank values in current API responses." + }, + { + "feature": "cell_values", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 3 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": false, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "number", + "value": 46057 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "date_standard", + "sheet": "cell_values", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'date', 'value': '2026-02-04'}, actual={'type': 'number', 'value': 46057}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": false, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "number", + "value": 46057.43802083333 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "datetime", + "sheet": "cell_values", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'datetime', 'value': '2026-02-04T10:30:45'}, actual={'type': 'number', 'value': 46057.43802083333}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "pylightxl", + "scores": { + "read": 3, + "write": 0 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_simple", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_unicode", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_empty", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_long", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_newline", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_integer", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_float", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_negative", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_large", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_scientific", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": false, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "date_standard", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": false, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "datetime", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_true", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_false", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_div0", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_na", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_value", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "blank", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": "Known limitation: pylightxl cell-values write has date/boolean/error fidelity limits due to writer encoding behavior." + }, + { + "feature": "cell_values", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "cell_values", + "library": "pyexcel", + "scores": { + "read": 3, + "write": 0 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_simple", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_unicode", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_empty", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_long", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": false, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "string_newline", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_integer", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_float", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_negative", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_large", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": false, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "number_scientific", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": false, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "date_standard", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": false, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "datetime", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_true", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": false, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "boolean_false", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_div0", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_na", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "error_value", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": false, + "expected": { + "type": "blank" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "cell_values", + "operation": "write", + "test_case_id": "blank", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "xlwt", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "string_simple": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "pandas", + "scores": { + "read": 1, + "write": 3 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_div0", + "sheet": "cell_values", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_na", + "sheet": "cell_values", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_value", + "sheet": "cell_values", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "string_simple": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "openpyxl-readonly", + "scores": { + "read": 3, + "write": null + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "polars", + "scores": { + "read": 1, + "write": null + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.141592654 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_div0", + "sheet": "cell_values", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#DIV/0!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_na", + "sheet": "cell_values", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#N/A'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": false, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "error_value", + "sheet": "cell_values", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'error', 'value': '#VALUE!'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "tablib", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "string_simple": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Hello World" + }, + "actual": { + "type": "string", + "value": "Hello World" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - simple" + } + }, + "string_unicode": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "actual": { + "type": "string", + "value": "\u65e5\u672c\u8a9e\ud83c\udf89\u00e9mojis" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - unicode" + } + }, + "string_empty": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - empty" + } + }, + "string_long": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "actual": { + "type": "string", + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - long (1000 chars)" + } + }, + "string_newline": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "actual": { + "type": "string", + "value": "Line 1\nLine 2\nLine 3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "String - with newlines" + } + }, + "number_integer": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 42 + }, + "actual": { + "type": "number", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - integer" + } + }, + "number_float": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 3.14159265358979 + }, + "actual": { + "type": "number", + "value": 3.14159265358979 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - float" + } + }, + "number_negative": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": -100.5 + }, + "actual": { + "type": "number", + "value": -100.5 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - negative" + } + }, + "number_large": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1234567890123456 + }, + "actual": { + "type": "number", + "value": 1234567890123456 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - large" + } + }, + "number_scientific": { + "read": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + }, + "write": { + "passed": true, + "expected": { + "type": "number", + "value": 1.23e-10 + }, + "actual": { + "type": "number", + "value": 1.23e-10 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Number - scientific notation" + } + }, + "date_standard": { + "read": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + }, + "write": { + "passed": true, + "expected": { + "type": "date", + "value": "2026-02-04" + }, + "actual": { + "type": "date", + "value": "2026-02-04" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Date - standard" + } + }, + "datetime": { + "read": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + }, + "write": { + "passed": true, + "expected": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "actual": { + "type": "datetime", + "value": "2026-02-04T10:30:45" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DateTime - with time" + } + }, + "boolean_true": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "boolean", + "value": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - TRUE" + } + }, + "boolean_false": { + "read": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + }, + "write": { + "passed": true, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "boolean", + "value": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Boolean - FALSE" + } + }, + "error_div0": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#DIV/0!" + }, + "actual": { + "type": "error", + "value": "#DIV/0!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #DIV/0!" + } + }, + "error_na": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#N/A" + }, + "actual": { + "type": "error", + "value": "#N/A" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #N/A" + } + }, + "error_value": { + "read": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + }, + "write": { + "passed": true, + "expected": { + "type": "error", + "value": "#VALUE!" + }, + "actual": { + "type": "error", + "value": "#VALUE!" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Error - #VALUE!" + } + }, + "blank": { + "read": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + }, + "write": { + "passed": true, + "expected": { + "type": "blank" + }, + "actual": { + "type": "blank" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Blank cell" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got blank", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got error" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got error", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "formulas", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got error" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got error", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "formula_sum": { + "write": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "write", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "write": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "write", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "write": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "write", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "write": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "write", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "pandas", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got blank", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "openpyxl-readonly", + "scores": { + "read": 3, + "write": null + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got blank", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "tablib", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "formula_sum": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_sum", + "sheet": "formulas", + "cell": "B2" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - SUM" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "actual": { + "type": "formula", + "formula": "=SUM(1,2,3)" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - SUM" + } + }, + "formula_cell_ref": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "error": "Expected formula, got error" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cell_ref", + "sheet": "formulas", + "cell": "B3" + }, + "adapter_message": "RuntimeError: Expected formula, got error", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cell reference" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A3*2" + }, + "actual": { + "type": "formula", + "formula": "=A3*2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cell reference" + } + }, + "formula_concat": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "error": "Expected formula, got string" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_concat", + "sheet": "formulas", + "cell": "B4" + }, + "adapter_message": "RuntimeError: Expected formula, got string", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - concat" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "actual": { + "type": "formula", + "formula": "=A4&\" \"&A5" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - concat" + } + }, + "formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "error": "Expected formula, got number" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "formulas", + "operation": "read", + "test_case_id": "formula_cross_sheet", + "sheet": "formulas", + "cell": "B5" + }, + "adapter_message": "RuntimeError: Expected formula, got number", + "probable_cause": "Adapter could not return a comparable value for this assertion.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Formula - cross sheet" + }, + "write": { + "passed": true, + "expected": { + "type": "formula", + "formula": "='References'!B2" + }, + "actual": { + "type": "formula", + "formula": "='References'!B2" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Formula - cross sheet" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bold": { + "read": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 12.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bold": { + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Calibri", + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Calibri", + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Calibri", + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Calibri", + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 0 + }, + "test_cases": { + "bold": { + "read": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": false, + "expected": { + "bold": true + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": false, + "expected": { + "italic": true + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_single", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "single", + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={'underline': 'single', 'font_name': 'Aptos Narrow', 'font_size': 12.0, 'font_color': '#000000'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_double", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "strikethrough", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold_italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 8.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_8", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 14.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_14", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 24.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_24", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 36.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_36", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_arial", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_times", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_courier", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "error": "aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "combined", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support write_cell_format: aspose-cells-foss supports only a single underline, not accounting or double variants.", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss supports only a single underline, not accounting or double variants.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bold": { + "read": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 8.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 14.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 24.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 36.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 12.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": false, + "expected": { + "bold": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": false, + "expected": { + "italic": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_single", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_double", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "strikethrough", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold_italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_8", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_14", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_24", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_36", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_arial", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_times", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_courier", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "combined", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "text_formatting", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": false, + "expected": { + "bold": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": false, + "expected": { + "italic": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_single", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_double", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "strikethrough", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold_italic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_8", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_14", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_24", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_36", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_arial", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_times", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_courier", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "combined", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlwt", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "bold": { + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Arial", + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Arial", + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Arial", + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Arial", + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 10.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "font_color": "#008000" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Arial', 'font_size': 10.0, 'font_color': '#008000'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "font_color": "#993300" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Arial', 'font_size': 10.0, 'font_color': '#993300'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Arial", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": false, + "expected": { + "bold": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": false, + "expected": { + "italic": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bold": { + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Calibri", + "font_size": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Calibri", + "font_size": 14.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Calibri", + "font_size": 24.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Calibri", + "font_size": 36.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "write": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "write": { + "passed": true, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Courier New", + "font_size": 11.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "write": { + "passed": true, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "bold": true, + "font_name": "Calibri", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bold": { + "read": { + "passed": false, + "expected": { + "bold": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold" + }, + "write": { + "passed": false, + "expected": { + "bold": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold", + "sheet": "text_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "read": { + "passed": false, + "expected": { + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Italic" + }, + "write": { + "passed": false, + "expected": { + "italic": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "italic", + "sheet": "text_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "read": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - single" + }, + "write": { + "passed": false, + "expected": { + "underline": "single" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_single", + "sheet": "text_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'single'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "read": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Underline - double" + }, + "write": { + "passed": false, + "expected": { + "underline": "double" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "underline_double", + "sheet": "text_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'underline': 'double'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "read": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Strikethrough" + }, + "write": { + "passed": false, + "expected": { + "strikethrough": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "strikethrough", + "sheet": "text_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'strikethrough': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "read": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Bold + Italic" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "bold_italic", + "sheet": "text_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "read": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + }, + "write": { + "passed": false, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_8", + "sheet": "text_formatting", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 8}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "read": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + }, + "write": { + "passed": false, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_14", + "sheet": "text_formatting", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 14}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "read": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + }, + "write": { + "passed": false, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_24", + "sheet": "text_formatting", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 24}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "read": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + }, + "write": { + "passed": false, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_size_36", + "sheet": "text_formatting", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_size': 36}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "read": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_arial", + "sheet": "text_formatting", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Arial" + } + }, + "font_times": { + "read": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_times", + "sheet": "text_formatting", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Times New Roman" + } + }, + "font_courier": { + "read": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + }, + "write": { + "passed": false, + "expected": { + "font_name": "Courier New" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "font_courier", + "sheet": "text_formatting", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_red", + "sheet": "text_formatting", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_blue", + "sheet": "text_formatting", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "read": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_green", + "sheet": "text_formatting", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "text_formatting", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + } + }, + "combined": { + "read": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "read", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + }, + "write": { + "passed": false, + "expected": { + "bold": true, + "font_size": 16, + "font_color": "#FF0000" + }, + "actual": { + "font_name": "Calibri", + "font_size": 11.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "text_formatting", + "operation": "write", + "test_case_id": "combined", + "sheet": "text_formatting", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 11.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bg_red": { + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_green", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "background_colors", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_green", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlwt", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "bg_red": { + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "write": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#008000" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={'bg_color': '#008000'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "write": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#993300" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={'bg_color': '#993300'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bg_red": { + "write": { + "passed": true, + "expected": { + "bg_color": "#FF0000" + }, + "actual": { + "bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "write": { + "passed": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "write": { + "passed": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "write": { + "passed": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "bg_red": { + "read": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_red", + "sheet": "background_colors", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - red" + } + }, + "bg_blue": { + "read": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_blue", + "sheet": "background_colors", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - blue" + } + }, + "bg_green": { + "read": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#00FF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_green", + "sheet": "background_colors", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - green" + } + }, + "bg_custom": { + "read": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "read", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "bg_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "background_colors", + "operation": "write", + "test_case_id": "bg_custom", + "sheet": "background_colors", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Background - custom (#8B4513)" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_currency", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_percent", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_date", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_scientific", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_custom_text", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "number_formats", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_currency", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_percent", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_date", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_scientific", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_custom_text", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlwt", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "numfmt_currency": { + "write": { + "passed": true, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "$#,##0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "0.00%" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "write": { + "passed": true, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "yyyy-mm-dd" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "write": { + "passed": true, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "0.00E+00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "write": { + "passed": true, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD\" 0.00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "numfmt_currency": { + "read": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + }, + "write": { + "passed": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_currency", + "sheet": "number_formats", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - currency" + } + }, + "numfmt_percent": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00%" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_percent", + "sheet": "number_formats", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - percent" + } + }, + "numfmt_date": { + "read": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + }, + "write": { + "passed": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_date", + "sheet": "number_formats", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - date" + } + }, + "numfmt_scientific": { + "read": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + }, + "write": { + "passed": false, + "expected": { + "number_format": "0.00E+00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_scientific", + "sheet": "number_formats", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - scientific" + } + }, + "numfmt_custom_text": { + "read": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "read", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + }, + "write": { + "passed": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "General" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "number_formats", + "operation": "write", + "test_case_id": "numfmt_custom_text", + "sheet": "number_formats", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'number_format': '\"USD\" 0.00'}, actual={'number_format': 'General'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Format - custom text" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "h_left": { + "read": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "h_left": { + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "h_align": "left", + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": "Known limitation: python-calamine alignment read is limited because its API does not expose style/alignment metadata." + }, + { + "feature": "alignment", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 1 + }, + "test_cases": { + "h_left": { + "read": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "h_left": { + "read": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_left", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_center", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_right", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_top", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_center", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "wrap_text", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "rotation_45", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": { + "error": "pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "indent_2", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": "Known limitation: pylightxl alignment write is a no-op because the library does not support formatting writes." + }, + { + "feature": "alignment", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "alignment", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_left", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_center", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_right", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_top", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_center", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "wrap_text", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "rotation_45", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": { + "error": "pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "indent_2", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "xlwt", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "h_left": { + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left", + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center", + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right", + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "write": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "v_align": "bottom", + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "v_align": "bottom", + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "v_align": "bottom", + "indent": 2 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "h_left": { + "write": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "write": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "write": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "h_align": "left", + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "h_left": { + "read": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + }, + "write": { + "passed": false, + "expected": { + "h_align": "left" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_left", + "sheet": "alignment", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'left'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - left" + } + }, + "h_center": { + "read": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "h_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_center", + "sheet": "alignment", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "h_right": { + "read": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + }, + "write": { + "passed": false, + "expected": { + "h_align": "right" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "h_right", + "sheet": "alignment", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'h_align': 'right'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - right" + } + }, + "v_top": { + "read": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": false, + "expected": { + "v_align": "top" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_top", + "sheet": "alignment", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'top'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": false, + "expected": { + "v_align": "center" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_center", + "sheet": "alignment", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'center'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": false, + "expected": { + "v_align": "bottom" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "v_bottom", + "sheet": "alignment", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": false, + "expected": { + "wrap": true + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "wrap_text", + "sheet": "alignment", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'wrap': True}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": false, + "expected": { + "rotation": 45 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "rotation_45", + "sheet": "alignment", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'rotation': 45}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "read", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": false, + "expected": { + "indent": 2 + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "alignment", + "operation": "write", + "test_case_id": "indent_2", + "sheet": "alignment", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'indent': 2}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Align - indent 2" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "thin_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "write": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "write": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 1 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thin_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "medium_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thick_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "double", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dashed", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dotted", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "top_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "bottom_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "left_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "right_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_styles", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "error": "pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "borders", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thin_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "medium_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thick_all", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "double", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dashed", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dotted", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot_dot", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "top_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "bottom_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "left_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "right_only", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_red", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_blue", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_styles", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "error": "pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells", + "probable_cause": "pyexcel exposes value-only cells", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel exposes value-only cells", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlwt", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "thin_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={'border_diagonal_down': 'thin'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={'border_diagonal_up': 'thin'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#993300" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={'border_style': 'thin', 'border_color': '#993300'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#008000", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={'border_top_color': '#FF0000', 'border_bottom_color': '#008000', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00', 'border_style': 'thin'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "thin_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "border_style": "thin", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "write": { + "passed": true, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "border_style": "medium", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "write": { + "passed": true, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "border_style": "thick", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "write": { + "passed": true, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "border_style": "double", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "write": { + "passed": true, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "write": { + "passed": true, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "border_style": "dotted", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "write": { + "passed": true, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "write": { + "passed": true, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "border_top": "thin", + "border_top_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "border_bottom": "thin", + "border_bottom_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "border_left": "thin", + "border_left_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "write": { + "passed": true, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "border_right": "thin", + "border_right_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "border_diagonal_up": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "write": { + "passed": true, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "write": { + "passed": true, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "write": { + "passed": true, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed", + "border_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "write": { + "passed": true, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00", + "border_style": "thin" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + } + }, + "medium_all": { + "read": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'medium', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + } + }, + "thick_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thick', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + } + }, + "double": { + "read": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - double line" + } + }, + "dashed": { + "read": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + } + }, + "dotted": { + "read": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + } + }, + "dash_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + } + }, + "dash_dot_dot": { + "read": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'dashDotDot', 'border_color': '#000000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + } + }, + "top_only": { + "read": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thin', 'border_bottom': None, 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - top only" + } + }, + "bottom_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': 'thin', 'border_left': None, 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - bottom only" + } + }, + "left_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': 'thin', 'border_right': None}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - left only" + } + }, + "right_only": { + "read": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': None, 'border_bottom': None, 'border_left': None, 'border_right': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - right only" + } + }, + "diagonal_up": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal up" + } + }, + "diagonal_down": { + "read": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal down" + } + }, + "diagonal_both": { + "read": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - diagonal both" + } + }, + "color_red": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - red color" + } + }, + "color_blue": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + } + }, + "color_custom": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + } + }, + "mixed_styles": { + "read": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thick", + "border_bottom": "thin", + "border_left": "medium", + "border_right": "dashed" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top': 'thick', 'border_bottom': 'thin', 'border_left': 'medium', 'border_right': 'dashed'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Border - mixed styles per edge" + } + }, + "mixed_colors": { + "read": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + }, + "write": { + "passed": false, + "expected": { + "border_top_color": "#FF0000", + "border_bottom_color": "#00FF00", + "border_left_color": "#0000FF", + "border_right_color": "#FFFF00" + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "borders", + "operation": "write", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "Expected values did not match actual values: expected={'border_top_color': '#FF0000', 'border_bottom_color': '#00FF00', 'border_left_color': '#0000FF', 'border_right_color': '#FFFF00'}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Border - mixed colors per edge" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "row_height_30": { + "write": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "write": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 3 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.83203125 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 20.83203125}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.83203125 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 8.83203125}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": true, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": 30.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "error": "pylightxl does not support set_row_height: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": null, + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "error": "pylightxl does not support set_row_height: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": null, + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "error": "pylightxl does not support set_row_height: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_20", + "sheet": null, + "cell": "D4" + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "error": "pylightxl does not support set_row_height: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_8", + "sheet": null, + "cell": "E5" + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "dimensions", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "error": "pyexcel does not support set_row_height: pyexcel does not expose row dimension writing" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": null, + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing", + "probable_cause": "pyexcel does not expose row dimension writing", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose row dimension writing", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "error": "pyexcel does not support set_row_height: pyexcel does not expose row dimension writing" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": null, + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing", + "probable_cause": "pyexcel does not expose row dimension writing", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose row dimension writing", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "error": "pyexcel does not support set_row_height: pyexcel does not expose row dimension writing" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_20", + "sheet": null, + "cell": "D4" + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing", + "probable_cause": "pyexcel does not expose row dimension writing", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose row dimension writing", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "error": "pyexcel does not support set_row_height: pyexcel does not expose row dimension writing" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_8", + "sheet": null, + "cell": "E5" + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing", + "probable_cause": "pyexcel does not expose row dimension writing", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose row dimension writing", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlwt", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "row_height_30": { + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 13.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 13.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 13.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 13.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 1 + }, + "test_cases": { + "row_height_30": { + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "write": { + "passed": true, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 20.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "write": { + "passed": true, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 8.0 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "row_height_30": { + "read": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + }, + "write": { + "passed": false, + "expected": { + "row_height": 30 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_30", + "sheet": "dimensions", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 30" + } + }, + "row_height_45": { + "read": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + }, + "write": { + "passed": false, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "row_height_45", + "sheet": "dimensions", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Row height - 45" + } + }, + "col_width_20": { + "read": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + }, + "write": { + "passed": false, + "expected": { + "column_width": 20 + }, + "actual": { + "column_width": 13.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_20", + "sheet": "dimensions", + "cell": "D4" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 13.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - D = 20" + } + }, + "col_width_8": { + "read": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "read", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + }, + "write": { + "passed": false, + "expected": { + "column_width": 8 + }, + "actual": { + "column_width": 13.0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "dimensions", + "operation": "write", + "test_case_id": "col_width_8", + "sheet": "dimensions", + "cell": "E5" + }, + "adapter_message": "Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 13.0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Column width - E = 8" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "python-calamine", + "scores": { + "read": 3, + "write": null + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "pylightxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "multiple_sheets", + "library": "pyexcel", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlwt", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "pandas", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "openpyxl-readonly", + "scores": { + "read": 3, + "write": null + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "polars", + "scores": { + "read": 1, + "write": null + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": false, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "multiple_sheets", + "operation": "read", + "test_case_id": "value_beta", + "sheet": "Beta", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'string', 'value': 'Beta'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": false, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "blank" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "multiple_sheets", + "operation": "read", + "test_case_id": "value_gamma", + "sheet": "Gamma", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'string', 'value': 'Gamma'}, actual={'type': 'blank'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "tablib", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "sheet_names": { + "read": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + }, + "write": { + "passed": true, + "expected": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "actual": { + "sheet_names": [ + "Alpha", + "Beta", + "Gamma" + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Sheet names" + } + }, + "value_alpha": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Alpha" + }, + "actual": { + "type": "string", + "value": "Alpha" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Alpha value" + } + }, + "value_beta": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Beta" + }, + "actual": { + "type": "string", + "value": "Beta" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Beta value" + } + }, + "value_gamma": { + "read": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + }, + "write": { + "passed": true, + "expected": { + "type": "string", + "value": "Gamma" + }, + "actual": { + "type": "string", + "value": "Gamma" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Gamma value" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "error": "pylightxl does not support merge_cells: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_horizontal", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "error": "pylightxl does not support merge_cells: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_vertical", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "error": "pylightxl does not support merge_cells: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_value_off_top_left", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "error": "pylightxl does not support merge_cells: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_top_left_fill", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "merged_cells", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "error": "pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_horizontal", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "error": "pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_vertical", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "error": "pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_value_off_top_left", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "error": "pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_top_left_fill", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "merge_horizontal": { + "write": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': 'B2:D2', 'top_left_value': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "write": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': 'B3:B5', 'top_left_value': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "write": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": null, + "non_top_left_nonempty": 0 + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': 'B6:D6', 'top_left_value': None, 'non_top_left_nonempty': 0}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "write": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": null, + "top_left_bg_color": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': 'B7:D7', 'top_left_value': None, 'top_left_bg_color': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "merge_horizontal": { + "write": { + "passed": true, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "write": { + "passed": true, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "write": { + "passed": true, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "write": { + "passed": true, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "merge_horizontal": { + "read": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B2:D2", + "top_left_value": "Merged" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_horizontal", + "sheet": "merged_cells", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B2:D2', 'top_left_value': 'Merged'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge horizontal B2:D2" + } + }, + "merge_vertical": { + "read": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B3:B5", + "top_left_value": "Vertical" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_vertical", + "sheet": "merged_cells", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B3:B5', 'top_left_value': 'Vertical'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "basic", + "label": "Merge vertical B3:B5" + } + }, + "merge_value_off_top_left": { + "read": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B6:D6", + "top_left_value": "OffTop", + "non_top_left_nonempty": 0 + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_value_off_top_left", + "sheet": "merged_cells", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B6:D6', 'top_left_value': 'OffTop', 'non_top_left_nonempty': 0}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "merge_drift", + "suggested_next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "explanation": { + "code": "merge_drift", + "summary": "merged-cell metadata changed", + "probable_cause": "merged range XML or non-anchor cell handling differs", + "next_step": "inspect mergeCells in the worksheet XML and subordinate cell behavior", + "tag": "merge" + } + } + ], + "importance": "edge", + "label": "Merge with non-top-left value" + } + }, + "merge_top_left_fill": { + "read": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "read", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + }, + "write": { + "passed": false, + "expected": { + "merged_range": "B7:D7", + "top_left_value": "Fill", + "top_left_bg_color": "#FF0000" + }, + "actual": { + "merged_range": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "merged_cells", + "operation": "write", + "test_case_id": "merge_top_left_fill", + "sheet": "merged_cells", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'merged_range': 'B7:D7', 'top_left_value': 'Fill', 'top_left_bg_color': '#FF0000'}, actual={'merged_range': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Merge with top-left fill" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "cf_cell_gt": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "wolfxl", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": {} + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'format': {}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": {} + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'format': {}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": {} + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'format': {}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": {} + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': True, 'format': {}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "error": "pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "conditional_formatting", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "error": "pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "error": "xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting", + "probable_cause": "xlwt cannot author conditional formatting", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author conditional formatting", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "cf_cell_gt": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "format": { + "bg_color": "#FF00FF" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "format": { + "bg_color": "#FFFF00" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "write": { + "passed": true, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "cf_cell_gt": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "cellIs", + "operator": "greaterThan", + "formula": "5", + "priority": 1, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'priority': 1, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "CF: cell > 5 (yellow fill)" + } + }, + "cf_formula_cross_sheet": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=Ref!$A$1>5", + "priority": 2, + "format": { + "bg_color": "#FF00FF" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'priority': 2, 'format': {'bg_color': '#FF00FF'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: formula rule with cross-sheet ref" + } + }, + "cf_text_contains": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "expression", + "formula": "=ISNUMBER(SEARCH(\"foo\",B2))", + "priority": 3, + "format": { + "bg_color": "#FFFF00" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'priority': 3, 'format': {'bg_color': '#FFFF00'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: text contains" + } + }, + "cf_data_bar": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'dataBar', 'priority': 4}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "CF: data bar" + } + }, + "cf_color_scale": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B2:B6', 'rule_type': 'colorScale', 'priority': 5}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + } + }, + "cf_stop_if_true": { + "read": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "priority": 1, + "stop_if_true": true, + "format": { + "bg_color": "#FF0000" + } + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "conditional_formatting", + "operation": "write", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: expected={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'priority': 1, 'stop_if_true': True, 'format': {'bg_color': '#FF0000'}}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "CF: stop-if-true priority" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "dv_list_csv": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "error": "pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "error": "pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "data_validation", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "error": "pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "error": "pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "error": "xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations", + "probable_cause": "xlwt cannot author data validations", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author data validations", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations", + "probable_cause": "xlwt cannot author data validations", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author data validations", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations", + "probable_cause": "xlwt cannot author data validations", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author data validations", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations", + "probable_cause": "xlwt cannot author data validations", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author data validations", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "error": "xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations", + "probable_cause": "xlwt cannot author data validations", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author data validations", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "dv_list_csv": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "write": { + "passed": true, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "dv_list_csv": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B2", + "validation_type": "list", + "formula1": "\"Red,Green,Blue\"", + "allow_blank": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B2', 'validation_type': 'list', 'formula1': '\"Red,Green,Blue\"', 'allow_blank': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: list from CSV" + } + }, + "dv_list_range": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B3', 'validation_type': 'list', 'formula1': '=$D$2:$D$4'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + } + }, + "dv_cross_sheet": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + } + }, + "dv_custom_formula": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B5', 'validation_type': 'custom', 'formula1': '=B5>C5'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + } + }, + "dv_whole_between": { + "read": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B6", + "validation_type": "whole", + "operator": "between", + "formula1": "1", + "formula2": "10", + "allow_blank": false, + "error_title": "Invalid", + "error": "Enter 1-10" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "data_validation", + "operation": "write", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'validation': {'range': 'B6', 'validation_type': 'whole', 'operator': 'between', 'formula1': '1', 'formula2': '10', 'allow_blank': False, 'error_title': 'Invalid', 'error': 'Enter 1-10'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "data_validation_drift", + "suggested_next_step": "inspect dataValidations in the worksheet XML", + "explanation": { + "code": "data_validation_drift", + "summary": "data validation metadata changed", + "probable_cause": "validation type, formula, or target range was dropped or rewritten", + "next_step": "inspect dataValidations in the worksheet XML", + "tag": "validation" + } + } + ], + "importance": "basic", + "label": "DV: whole number with error" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "link_external": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "link_external": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "aspose-cells-foss", + "scores": { + "read": 0, + "write": 3 + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": null, + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': None, 'tooltip': 'Go to docs', 'internal': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": null, + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': None, 'tooltip': 'Jump to target', 'internal': True}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": null, + "tooltip": "Send email", + "internal": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': None, 'tooltip': 'Send email', 'internal': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": null, + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': None, 'tooltip': 'Encoded URL', 'internal': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "link_external": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "error": "pylightxl does not support add_hyperlink: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "error": "pylightxl does not support add_hyperlink: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "error": "pylightxl does not support add_hyperlink: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "error": "pylightxl does not support add_hyperlink: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "hyperlinks", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "error": "pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "error": "pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "error": "pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "error": "pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "link_external": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "error": "xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "error": "xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "error": "xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "error": "xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt hyperlink metadata is not supported in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "link_external": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "write": { + "passed": true, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "link_external": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": "Go to docs", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_external", + "sheet": "hyperlinks", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': 'Go to docs', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: external URL" + } + }, + "link_internal": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": true + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_internal", + "sheet": "hyperlinks", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': True}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: internal sheet" + } + }, + "link_mailto": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B4", + "target": "mailto:test@example.com", + "display": "Email", + "tooltip": "Send email", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_mailto", + "sheet": "hyperlinks", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': 'Send email', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "basic", + "label": "Hyperlink: mailto" + } + }, + "link_long": { + "read": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "read", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + }, + "write": { + "passed": false, + "expected": { + "hyperlink": { + "cell": "B5", + "target": "https://example.com/search?q=excel%20bench&sort=desc#section-2", + "display": "Search", + "tooltip": "Encoded URL", + "internal": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "hyperlinks", + "operation": "write", + "test_case_id": "link_long", + "sheet": "hyperlinks", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': 'Encoded URL', 'internal': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "hyperlink_drift", + "suggested_next_step": "inspect worksheet hyperlinks and worksheet rels", + "explanation": { + "code": "hyperlink_drift", + "summary": "hyperlink target or display metadata changed", + "probable_cause": "hyperlink rel target, tooltip, or internal location was not preserved", + "next_step": "inspect worksheet hyperlinks and worksheet rels", + "tag": "hyperlink" + } + } + ], + "importance": "edge", + "label": "Hyperlink: long encoded URL" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": true, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": true, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": true, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": true, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "image_one_cell": { + "write": { + "passed": true, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "write": { + "passed": true, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "aspose-cells-foss", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind." + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "probable_cause": "aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "probable_cause": "aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind." + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support read_images: aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "probable_cause": "aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support add_image: aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "probable_cause": "aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss writes only two-cell picture anchors, while the benchmark requires one-cell anchors.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": true, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": true, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": true, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": true, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "pylightxl does not support add_image: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "pylightxl does not support add_image: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "images", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "pyexcel does not support add_image: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "pyexcel does not support add_image: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": { + "error": "xlwt does not support add_image: xlwt cannot embed images in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter", + "probable_cause": "xlwt cannot embed images in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot embed images in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": { + "error": "xlwt does not support add_image: xlwt cannot embed images in this adapter" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter", + "probable_cause": "xlwt cannot embed images in this adapter", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot embed images in this adapter", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "images", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "image_one_cell": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "B2", + "path": "fixtures/images/sample.png", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_one_cell", + "sheet": "images", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'B2', 'path': 'fixtures/images/sample.png', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Image: one-cell anchor" + } + }, + "image_two_cell_offset": { + "read": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + }, + "write": { + "passed": false, + "expected": { + "image": { + "cell": "D6", + "path": "fixtures/images/sample.jpg", + "anchor": "oneCell" + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "images", + "operation": "write", + "test_case_id": "image_two_cell_offset", + "sheet": "images", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'image': {'cell': 'D6', 'path': 'fixtures/images/sample.jpg', 'anchor': 'oneCell'}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Image: two-cell anchor with offset" + } + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "openpyxl", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "python-calamine", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "aspose-cells-foss", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "wolfxl", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "pylightxl", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "pivot_tables", + "library": "pyexcel", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "xlwt", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "pandas", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "openpyxl-readonly", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "polars", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "pivot_tables", + "library": "tablib", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx)." + }, + { + "feature": "comments", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "comment_legacy": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "None:Legacy note", + "threaded": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={'comment': {'cell': 'B2', 'text': 'None:Legacy note', 'threaded': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "None:Threaded fallback", + "threaded": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={'comment': {'cell': 'B3', 'text': 'None:Threaded fallback', 'threaded': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "None:Another note", + "threaded": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={'comment': {'cell': 'B4', 'text': 'None:Another note', 'threaded': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": true, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "error": "pylightxl does not support add_comment: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "error": "pylightxl does not support add_comment: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "error": "pylightxl does not support add_comment: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "comments", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "error": "pyexcel does not support add_comment: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "error": "pyexcel does not support add_comment: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "error": "pyexcel does not support add_comment: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": { + "error": "xlwt does not support add_comment: xlwt cannot author comments" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments", + "probable_cause": "xlwt cannot author comments", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author comments", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": { + "error": "xlwt does not support add_comment: xlwt cannot author comments" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments", + "probable_cause": "xlwt cannot author comments", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author comments", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": { + "error": "xlwt does not support add_comment: xlwt cannot author comments" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments", + "probable_cause": "xlwt cannot author comments", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "xlwt cannot author comments", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "comment_legacy": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B2", + "text": "Legacy note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_legacy", + "sheet": "comments", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B2', 'text': 'Legacy note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "basic", + "label": "Comment: legacy note" + } + }, + "comment_threaded": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B3", + "text": "Threaded fallback", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_threaded", + "sheet": "comments", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: threaded" + } + }, + "comment_author": { + "read": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "read", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + }, + "write": { + "passed": false, + "expected": { + "comment": { + "cell": "B4", + "text": "Another note", + "threaded": false + } + }, + "actual": {}, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "comments", + "operation": "write", + "test_case_id": "comment_author", + "sheet": "comments", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', 'threaded': False}}, actual={}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "comment_drift", + "suggested_next_step": "inspect comments XML plus VML drawing relationships", + "explanation": { + "code": "comment_drift", + "summary": "comment metadata changed", + "probable_cause": "legacy comment text, author, or VML relationship was not preserved", + "next_step": "inspect comments XML plus VML drawing relationships", + "tag": "comment" + } + } + ], + "importance": "edge", + "label": "Comment: second author" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "freeze_b2": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "pylightxl does not support set_freeze_panes: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "pylightxl does not support set_freeze_panes: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "pylightxl does not support set_freeze_panes: pylightxl does not implement this feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature", + "probable_cause": "pylightxl does not implement this feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pylightxl does not implement this feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "freeze_panes", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature", + "probable_cause": "pyexcel does not expose this worksheet feature", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "pyexcel does not expose this worksheet feature", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "'Sheet' object has no attribute 'frozen_row_count'" + }, + "notes": "Exception: AttributeError", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "AttributeError: 'Sheet' object has no attribute 'frozen_row_count'", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "'Sheet' object has no attribute 'frozen_row_count'" + }, + "notes": "Exception: AttributeError", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "AttributeError: 'Sheet' object has no attribute 'frozen_row_count'", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "'Sheet' object has no attribute 'frozen_row_count'" + }, + "notes": "Exception: AttributeError", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "AttributeError: 'Sheet' object has no attribute 'frozen_row_count'", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "freeze_b2": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "write": { + "passed": true, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'B2'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + } + }, + "freeze_d5": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "freeze": { + "mode": null, + "top_left_cell": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'freeze', 'top_left_cell': 'D5'}}, actual={'freeze': {'mode': None, 'top_left_cell': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + } + }, + "split_2x1": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "freeze": { + "mode": null, + "x_split": null, + "y_split": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "freeze_panes", + "operation": "write", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'freeze': {'mode': 'split', 'x_split': 1, 'y_split': 2}}, actual={'freeze': {'mode': None, 'x_split': None, 'y_split': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "freeze_pane_drift", + "suggested_next_step": "inspect sheetViews/pane in the worksheet XML", + "explanation": { + "code": "freeze_pane_drift", + "summary": "freeze pane settings changed", + "probable_cause": "pane split/top-left metadata was dropped or normalized incorrectly", + "next_step": "inspect sheetViews/pane in the worksheet XML", + "tag": "freeze_pane" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": true, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": true, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "xlsxwriter does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "python-calamine does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "aspose-cells-foss", + "scores": { + "read": 2, + "write": 3 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": null + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': 'local'}, actual={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': None}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": true, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 2 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": true, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": true, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": true, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": true, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "name": "LocalName", + "scope": "not_found", + "refers_to": "" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "Expected values did not match actual values: expected={'name': 'LocalName', 'scope': 'sheet', 'refers_to': 'named_ranges!$B$5', 'value': 'local'}, actual={'name': 'LocalName', 'scope': 'not_found', 'refers_to': ''}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": true, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": true, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "named_range_scope_drift", + "suggested_next_step": "inspect workbook.xml definedNames and localSheetId values", + "explanation": { + "code": "named_range_scope_drift", + "summary": "named range metadata changed", + "probable_cause": "workbook-level vs sheet-level defined-name scope was lost or rewritten", + "next_step": "inspect workbook.xml definedNames and localSheetId values", + "tag": "named_range" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "pylightxl does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "named_ranges", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "pyexcel does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "pyexcel does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "xlwt does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "pandas does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: pandas does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "pandas does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "xlsxwriter-constmem does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "openpyxl-readonly does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "polars does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: polars does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "nr_simple_cell": { + "read": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_simple_cell", + "sheet": "named_ranges", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + }, + "write": { + "passed": false, + "expected": { + "name": "SingleCell", + "scope": "workbook", + "refers_to": "named_ranges!$B$2", + "value": 42 + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_simple_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: single cell" + } + }, + "nr_cell_range": { + "read": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cell_range", + "sheet": "named_ranges", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + }, + "write": { + "passed": false, + "expected": { + "name": "DataRange", + "scope": "workbook", + "refers_to": "named_ranges!$B$3:$D$3" + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cell_range", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: cell range" + } + }, + "nr_formula_ref": { + "read": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_formula_ref", + "sheet": "named_ranges", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + }, + "write": { + "passed": false, + "expected": { + "name": "TaxRate", + "scope": "workbook", + "refers_to": "named_ranges!$B$4", + "value": 0.08 + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_formula_ref", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Named range: used in formula" + } + }, + "nr_sheet_scope": { + "read": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_sheet_scope", + "sheet": "named_ranges", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + }, + "write": { + "passed": false, + "expected": { + "name": "LocalName", + "scope": "sheet", + "refers_to": "named_ranges!$B$5", + "value": "local" + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_sheet_scope", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: sheet-scoped" + } + }, + "nr_cross_sheet": { + "read": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_cross_sheet", + "sheet": "named_ranges", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + }, + "write": { + "passed": false, + "expected": { + "name": "OtherSheet", + "scope": "workbook", + "refers_to": "Targets!$A$1" + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_cross_sheet", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: cross-sheet reference" + } + }, + "nr_special_chars": { + "read": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "tablib does not implement named range reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "read", + "test_case_id": "nr_special_chars", + "sheet": "named_ranges", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: tablib does not implement named range reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + }, + "write": { + "passed": false, + "expected": { + "name": "_my_range", + "scope": "workbook", + "refers_to": "named_ranges!$B$7" + }, + "actual": { + "error": "tablib does not implement named range writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "named_ranges", + "operation": "write", + "test_case_id": "nr_special_chars", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement named range writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Named range: underscore name" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "xlsxwriter does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "python-calamine does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 1 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": false, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 0 + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": false, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 0 + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': True, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 1}}, actual={'table': {'name': 'Summary', 'ref': 'E7:G11', 'header_row': True, 'totals_row': False, 'style': 'TableStyleLight1', 'columns': ['Item', 'Count', 'Total'], 'totals_row_count': 0}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': None, 'columns': ['Key', 'Value']}}, actual={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium2', 'columns': ['Key', 'Value']}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': None, 'columns': ['Key', 'Value']}}, actual={'table': {'name': 'PlainTable', 'ref': 'E13:F16', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium2', 'columns': ['Key', 'Value']}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": true, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_cause": "formatting was dropped, defaulted, or normalized differently", + "next_step": "inspect styles.xml and the adapter's style mapping", + "tag": "style" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "pylightxl does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "tables", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "pyexcel does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "pyexcel does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "xlwt does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "pandas does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: pandas does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "pandas does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "openpyxl-readonly does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "polars does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: polars does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "tbl_basic": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SalesData", + "ref": "E2:G5", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Name", + "Qty", + "Price" + ] + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: basic 3-col" + } + }, + "tbl_with_totals": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Summary", + "ref": "E7:G11", + "header_row": true, + "totals_row": true, + "style": "TableStyleLight1", + "columns": [ + "Item", + "Count", + "Total" + ], + "totals_row_count": 1 + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: with totals row" + } + }, + "tbl_no_style": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Table: no style" + } + }, + "tbl_single_col": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: single column" + } + }, + "tbl_single_row": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: header only (no data rows)" + } + }, + "tbl_autofilter": { + "read": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "tablib does not implement table reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "NotImplementedError: tablib does not implement table reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + }, + "write": { + "passed": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "tablib does not implement table writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement table writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "xlsxwriter does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "xlsxwriter does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "xlsxwriter does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "python-calamine does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "python-calamine does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "python-calamine does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": true, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "pylightxl does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "pylightxl does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "pylightxl does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "sheet_protection", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "pyexcel does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "xlwt does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "xlwt does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "xlwt does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "pandas does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "pandas does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "pandas does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "pandas does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "pandas does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "pandas does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "openpyxl-readonly does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "openpyxl-readonly does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "openpyxl-readonly does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "polars does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "polars does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "polars does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "sheet_protection", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "prot_basic": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "tablib does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true + } + }, + "actual": { + "error": "tablib does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: basic (OOXML defaults)" + } + }, + "prot_password": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "tablib does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": true, + "format_cells": true, + "insert_rows": true, + "select_locked_cells": false, + "select_unlocked_cells": false, + "sort": true, + "auto_filter": true, + "password": "bench-secret" + } + }, + "actual": { + "error": "tablib does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Protection: with password hash" + } + }, + "prot_granular": { + "read": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "tablib does not implement sheet protection reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + }, + "write": { + "passed": false, + "expected": { + "protection": { + "protected": true, + "password_hash_present": false, + "format_cells": false, + "insert_rows": true, + "select_locked_cells": true, + "select_unlocked_cells": false, + "sort": false, + "auto_filter": true + } + }, + "actual": { + "error": "tablib does not implement sheet protection writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement sheet protection writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Protection: granular attribute flags" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": true, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlsxwriter does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlsxwriter does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "xlsxwriter does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "python-calamine does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "python-calamine does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "python-calamine does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "aspose-cells-foss", + "scores": { + "read": 1, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": 100, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'landscape', 'fit_to_width': 1, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'landscape', 'fit_to_width': 1, 'fit_to_height': None, 'scale': 100, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API.", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API.", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 100, + "print_title_rows": null, + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 100, 'print_title_rows': None, 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API." + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: aspose-cells-foss does not support set_page_setup: aspose-cells-foss has no print-title-rows API.", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "aspose-cells-foss has no print-title-rows API.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 2 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": true, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": true, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}, actual={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pylightxl does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pylightxl does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "exception", + "suggested_next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "explanation": { + "code": "exception", + "summary": "adapter raised instead of returning comparable workbook data", + "probable_cause": "adapter/runtime error interrupted the assertion path", + "next_step": "open the diagnostic adapter message and reproduce the adapter call directly", + "tag": "exception" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "pylightxl does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "page_setup", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pyexcel does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pyexcel does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pyexcel does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pyexcel does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "pyexcel does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "pyexcel does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlwt does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlwt does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "xlwt does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pandas does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pandas does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pandas does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "pandas does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "pandas does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "pandas does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "xlsxwriter-constmem does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "openpyxl-readonly does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "openpyxl-readonly does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "openpyxl-readonly does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "polars does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "polars does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "polars does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "page_setup_landscape": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "tablib does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "tablib does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_landscape", + "sheet": "page_setup_landscape", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: landscape + fit-to-width" + } + }, + "page_setup_scale": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "tablib does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": null, + "fit_to_height": null, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "actual": { + "error": "tablib does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Page setup: portrait at 75% scale" + } + }, + "page_setup_titles": { + "read": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "tablib does not implement page setup reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + }, + "write": { + "passed": false, + "expected": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P" + } + }, + "actual": { + "error": "tablib does not implement page setup writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_titles", + "sheet": "page_setup_titles", + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement page setup writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "openpyxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "xlsxwriter", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlsxwriter does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlsxwriter does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "python-calamine", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "python-calamine does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "python-calamine does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: python-calamine does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "aspose-cells-foss", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "wolfxl", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": true, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12" + } + ] + }, + "notes": null, + "diagnostics": [], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "pylightxl", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pylightxl does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "expected string or bytes-like object, got 'NoneType'" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: expected string or bytes-like object, got 'NoneType'", + "probable_cause": "Input workbook could not be opened by this adapter.", + "root_cause_code": "drawing_or_image_drift", + "suggested_next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "explanation": { + "code": "drawing_or_image_drift", + "summary": "image or drawing relationship changed", + "probable_cause": "media part may exist but worksheet drawing rels or anchors do not match", + "next_step": "inspect drawing XML, drawing rels, and xl/media package parts", + "tag": "drawing" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pylightxl does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pylightxl does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "xlrd", + "scores": { + "read": null, + "write": null + }, + "test_cases": {}, + "notes": "Not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "chart_anchor", + "library": "pyexcel", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pyexcel does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pyexcel does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pyexcel does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pyexcel does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pyexcel does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pyexcel does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "xlwt", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlwt does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlwt does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlwt does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "pandas", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pandas does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pandas does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pandas does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: pandas does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "pandas does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: pandas does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "xlsxwriter-constmem", + "scores": { + "read": null, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlsxwriter-constmem does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "xlsxwriter-constmem does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: xlsxwriter-constmem does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "openpyxl-readonly", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "openpyxl-readonly does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "openpyxl-readonly does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: openpyxl-readonly does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "polars", + "scores": { + "read": 0, + "write": null + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "polars does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "polars does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: polars does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + }, + { + "feature": "chart_anchor", + "library": "tablib", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "chart_bar": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "tablib does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "tablib does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Chart: bar with twoCell anchor" + } + }, + "chart_line": { + "read": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "tablib does not implement chart anchor reads" + }, + "notes": "Exception: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "NotImplementedError: tablib does not implement chart anchor reads", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter raised an exception while evaluating this test case.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + }, + "write": { + "passed": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "tablib does not implement chart anchor writes" + }, + "notes": "Write failed: NotImplementedError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "NotImplementedError: tablib does not implement chart anchor writes", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/scripts/build_calc_fixture.py b/scripts/build_calc_fixture.py new file mode 100755 index 0000000..ad7f99b --- /dev/null +++ b/scripts/build_calc_fixture.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 +"""Build the deterministic Formula Recalculation benchmark fixture. + +The canonical fixture is written by openpyxl and ships formulas with NO cached +values. LibreOffice's isolated, headless ``--convert-to xlsx`` path recalculates +a throwaway copy; every formula cache in that copy is verified before the +oracle JSON is written. Engines are scored against the oracle, so a passing +engine must produce the values itself rather than pass stored caches through. +""" + +from __future__ import annotations + +import json +import tempfile +from datetime import date, datetime +from pathlib import Path +from typing import Any + +from openpyxl import Workbook, load_workbook +from openpyxl.utils.datetime import to_excel + +from excelbench.harness.calc import libreoffice_version, recalculate_with_libreoffice + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_FIXTURE_PATH = REPOSITORY_ROOT / "fixtures" / "calc" / "financial_model.xlsx" +DEFAULT_EXPECTED_PATH = REPOSITORY_ROOT / "fixtures" / "calc" / "expected_values.json" + + +def build_fixture( + fixture_path: Path = DEFAULT_FIXTURE_PATH, + expected_path: Path = DEFAULT_EXPECTED_PATH, +) -> dict[str, Any]: + """Build a cache-free workbook, derive oracle values via LibreOffice, persist both. + + The canonical fixture keeps NO cached formula values: openpyxl writes the + formulas only. Expected values are harvested from a throwaway LibreOffice + recalculation copy. A passing engine must therefore produce the numbers + itself; passthrough of precomputed caches cannot score. + """ + fixture_path.parent.mkdir(parents=True, exist_ok=True) + workbook = _build_workbook() + workbook.save(fixture_path) + + formula_references = _formula_references(fixture_path) + with tempfile.TemporaryDirectory(prefix="excelbench-calc-oracle-") as temporary_dir: + recalculated_path = Path(temporary_dir) / "recalculated.xlsx" + recalculate_reason = recalculate_with_libreoffice( + fixture_path, recalculated_path + ) + if recalculate_reason is not None: + raise RuntimeError(recalculate_reason) + cells = _cached_cells(recalculated_path, formula_references) + _assert_fixture_cache_free(fixture_path, formula_references) + + expected = { + "oracle": f"libreoffice/{libreoffice_version() or 'unknown'}", + "cells": cells, + } + expected_path.parent.mkdir(parents=True, exist_ok=True) + expected_path.write_text(json.dumps(expected, indent=2, sort_keys=True) + "\n") + return expected + + +def _assert_fixture_cache_free( + fixture_path: Path, formula_references: list[str] +) -> None: + """Fail loudly if the canonical fixture ever ships cached formula values.""" + workbook = load_workbook(fixture_path, data_only=True, read_only=True) + try: + cached = [ + reference + for reference in formula_references + if workbook[reference.split("!", maxsplit=1)[0]][ + reference.split("!", maxsplit=1)[1] + ].value + is not None + ] + finally: + workbook.close() + if cached: + sample = ", ".join(sorted(cached)[:5]) + raise RuntimeError( + f"fixture must not ship cached formula values (found: {sample})" + ) + + +def _build_workbook() -> Workbook: + workbook = Workbook() + inputs = workbook.active + inputs.title = "Inputs" + schedule = workbook.create_sheet("Schedule") + summary = workbook.create_sheet("Summary") + _populate_inputs(inputs) + _populate_schedule(schedule) + _populate_summary(summary) + return workbook + + +def _populate_inputs(worksheet: Any) -> None: + worksheet["A1"] = "Financial model assumptions" + assumptions: list[tuple[str, Any]] = [ + ("Start Date", date(2025, 1, 31)), + ("Revenue Growth", 0.045), + ("Gross Margin", 0.62), + ("Fixed Costs", 12000.0), + ("Tax Rate", 0.24), + ("Discount Rate", 0.1), + ("Target Category", "Enterprise"), + ("Target Region", "West"), + ] + for row_index, (label, value) in enumerate(assumptions, start=2): + worksheet.cell(row=row_index, column=1, value=label) + worksheet.cell(row=row_index, column=2, value=value) + worksheet["B2"].number_format = "yyyy-mm-dd" + worksheet["B3"].number_format = "0.0%" + worksheet["B4"].number_format = "0.0%" + worksheet["B6"].number_format = "0.0%" + worksheet["B7"].number_format = "0.0%" + + headers = ["Record", "Category", "Units", "Price", "Launch Date", "Region"] + for column_index, header in enumerate(headers, start=1): + worksheet.cell(row=12, column=column_index, value=header) + categories = ("Enterprise", "SMB", "Consumer", "Enterprise", "SMB") + regions = ("West", "East", "South", "North") + for offset in range(40): + row_index = offset + 13 + worksheet.cell(row=row_index, column=1, value=offset + 1) + worksheet.cell( + row=row_index, column=2, value=categories[offset % len(categories)] + ) + worksheet.cell(row=row_index, column=3, value=20 + ((offset * 7) % 35)) + worksheet.cell( + row=row_index, column=4, value=125.0 + ((offset * 13) % 170) + 0.25 + ) + worksheet.cell(row=row_index, column=5, value=date(2025, (offset % 12) + 1, 1)) + worksheet.cell(row=row_index, column=6, value=regions[offset % len(regions)]) + + +def _populate_schedule(worksheet: Any) -> None: + worksheet["A1"] = "Metric" + for period in range(1, 13): + worksheet.cell(row=1, column=period + 1, value=period) + labels = [ + "Revenue", + "Cost of Goods Sold", + "Gross Profit", + "Fixed Costs", + "Target Units", + "Target Regional Price", + "Operating Costs", + "EBITDA", + "Tax", + "Cash Flow", + ] + for row_index, label in enumerate(labels, start=2): + worksheet.cell(row=row_index, column=1, value=label) + for column_index in range(2, 14): + column_letter = worksheet.cell(row=1, column=column_index).column_letter + formulas = { + 2: f"=100000*(1+Inputs!$B$3)^({column_letter}$1-1)", + 3: f"={column_letter}2*(1-Inputs!$B$4)", + 4: f"={column_letter}2-{column_letter}3", + 5: "=Inputs!$B$5", + 6: "=SUMIF(Inputs!$B$13:$B$52,Inputs!$B$8,Inputs!$C$13:$C$52)", + 7: "=SUMIFS(Inputs!$D$13:$D$52,Inputs!$B$13:$B$52,Inputs!$B$8," + "Inputs!$F$13:$F$52,Inputs!$B$9)", + 8: f"={column_letter}3+{column_letter}5+{column_letter}6*{column_letter}7+SUM(0)", + 9: f"={column_letter}2-{column_letter}8", + 10: f"=IF({column_letter}9>0,{column_letter}9*Inputs!$B$6,0)", + 11: f"={column_letter}9-{column_letter}10-{column_letter}2*0.08", + } + for row_index, formula in formulas.items(): + worksheet.cell(row=row_index, column=column_index, value=formula) + + +def _populate_summary(worksheet: Any) -> None: + worksheet["A1"] = "Summary Metric" + worksheet["B1"] = "Value" + formulas = { + "A2": "Positive cash flow flag", + "B2": "=IF(SUM(Schedule!B11:M11)>0,1,0)", + "A3": "Growth tier", + "B3": "=IF(Inputs!$B$3>=0.05,3,IF(Inputs!$B$3>=0.03,2,1))", + "A4": "Minimum EBITDA", + "B4": "=MIN(Schedule!B9:M9)", + "A5": "Maximum EBITDA", + "B5": "=MAX(Schedule!B9:M9)", + "A6": "Average cash flow", + "B6": "=ROUND(AVERAGE(Schedule!B11:M11),2)", + "A7": "VLOOKUP enterprise units", + "B7": '=VLOOKUP("Enterprise",Inputs!$B$13:$D$52,2,FALSE)', + "A8": "INDEX/MATCH enterprise price", + "B8": '=INDEX(Inputs!$D$13:$D$52,MATCH("Enterprise",Inputs!$B$13:$B$52,0))', + "A10": "Net present value", + "B10": "=NPV(Inputs!$B$7,Schedule!B11:M11)", + "A11": "Internal rate of return", + "B11": "=IRR(B18:N18)", + "A12": "Date plus three months", + "B12": "=EDATE(Inputs!$B$2,3)", + "A13": "Month end plus three months", + "B13": "=EOMONTH(Inputs!$B$2,3)", + "A14": "Enterprise records", + "B14": '=COUNTIF(Inputs!$B$13:$B$52,"Enterprise")', + "A15": "Enterprise west records", + "B15": '=COUNTIFS(Inputs!$B$13:$B$52,"Enterprise",Inputs!$F$13:$F$52,"West")', + } + for reference, value in formulas.items(): + worksheet[reference] = value + + worksheet["A17"] = "Signed cash-flow series for IRR" + cash_flows = [ + -100000.0, + 16500.0, + 18000.0, + 20500.0, + 23000.0, + 25000.0, + 27000.0, + 29500.0, + 31500.0, + 34000.0, + 36000.0, + 38500.0, + 41000.0, + ] + for column_index, cash_flow in enumerate(cash_flows, start=2): + worksheet.cell(row=18, column=column_index, value=cash_flow) + + +def _formula_references(fixture_path: Path) -> list[str]: + workbook = load_workbook(fixture_path, data_only=False, read_only=True) + try: + return [ + f"{worksheet.title}!{cell.coordinate}" + for worksheet in workbook.worksheets + for row in worksheet.iter_rows() + for cell in row + if isinstance(cell.value, str) and cell.value.startswith("=") + ] + finally: + workbook.close() + + +def _cached_cells( + fixture_path: Path, formula_references: list[str] +) -> dict[str, dict[str, Any]]: + workbook = load_workbook(fixture_path, data_only=True, read_only=True) + try: + cells: dict[str, dict[str, Any]] = {} + for reference in formula_references: + sheet_name, cell_reference = reference.split("!", maxsplit=1) + value = workbook[sheet_name][cell_reference].value + if value is None: + raise RuntimeError( + f"LibreOffice left an empty cached formula value at {reference}" + ) + cells[reference] = _expected_cell(value) + return cells + finally: + workbook.close() + + +def _expected_cell(value: Any) -> dict[str, Any]: + if isinstance(value, bool): + return {"value": value, "type": "bool"} + if isinstance(value, (int, float)): + return {"value": round(float(value), 10), "type": "number"} + if isinstance(value, (date, datetime)): + return {"value": round(float(to_excel(value)), 10), "type": "number"} + if isinstance(value, str): + return {"value": value, "type": "string"} + raise TypeError(f"Unsupported cached formula value: {value!r}") + + +def main() -> int: + """Build the fixture and report formula coverage with representative values.""" + expected = build_fixture() + cells = expected["cells"] + print(f"Formula cells: {len(cells)}") + for reference in sorted(cells)[:3]: + print(f"{reference}: {cells[reference]}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/build_mutation_template.py b/scripts/build_mutation_template.py new file mode 100755 index 0000000..31ffcd0 --- /dev/null +++ b/scripts/build_mutation_template.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python3 +"""Build the deterministic mutation-fidelity workbook fixture.""" + +from __future__ import annotations + +import hashlib +import json +import re +import tempfile +import xml.etree.ElementTree as ET +from pathlib import Path +from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo + +from openpyxl import Workbook +from openpyxl.chart import BarChart, LineChart, Reference +from openpyxl.comments import Comment +from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor +from openpyxl.formatting.rule import CellIsRule, ColorScaleRule +from openpyxl.styles import Font, PatternFill +from openpyxl.utils import get_column_letter +from openpyxl.workbook.defined_name import DefinedName +from openpyxl.worksheet.datavalidation import DataValidation +from openpyxl.worksheet.table import Table, TableStyleInfo + +REPO_ROOT = Path(__file__).resolve().parents[1] +FIXTURE_DIR = REPO_ROOT / "fixtures" / "mutation" +FIXTURE_PATH = FIXTURE_DIR / "template_corporate_model.xlsx" +MANIFEST_PATH = FIXTURE_DIR / "manifest.json" +FIXED_TIMESTAMP = (2026, 1, 1, 0, 0, 0) +GENERATED_AT = "2026-01-01T00:00:00Z" +_CONTENT_TYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types" +_RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships" +_OFFICE_DOCUMENT_REL_NS = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships" +) + + +def _anchor(from_cell: str, to_cell: str) -> TwoCellAnchor: + """Create the explicit two-cell anchor used by the OpenPyXL adapter.""" + from_col = ord(from_cell[0].upper()) - ord("A") + from_row = int(from_cell[1:]) - 1 + to_col = ord(to_cell[0].upper()) - ord("A") + to_row = int(to_cell[1:]) - 1 + return TwoCellAnchor( + _from=AnchorMarker(col=from_col, colOff=0, row=from_row, rowOff=0), + to=AnchorMarker(col=to_col, colOff=0, row=to_row, rowOff=0), + ) + + +def _make_workbook(path: Path) -> None: + """Build the structural workbook before custom XML injection.""" + workbook = Workbook() + inputs = workbook.active + inputs.title = "Inputs" + schedule = workbook.create_sheet("Schedule") + summary = workbook.create_sheet("Summary") + workbook.properties.created = "2026-01-01T00:00:00Z" + workbook.properties.modified = "2026-01-01T00:00:00Z" + + headers = ["Driver", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "Q7"] + inputs.append(headers) + for row_index in range(2, 42): + inputs.cell(row_index, 1, f"Input {row_index - 1:02d}") + for column_index in range(2, 9): + inputs.cell(row_index, column_index, (row_index - 1) * column_index * 10) + for cell in inputs[1]: + cell.font = Font(bold=True, color="FFFFFF") + cell.fill = PatternFill("solid", fgColor="1F4E78") + for column_index in range(1, 9): + inputs.column_dimensions[get_column_letter(column_index)].width = 14 + inputs.freeze_panes = "B2" + inputs["A2"].hyperlink = "https://example.com/corporate-model-inputs" + inputs["A2"].comment = Comment("Mutation target workbook input.", "ExcelBench") + + inputs_table = Table(displayName="CorporateInputs", ref="A1:H41") + inputs_table.tableStyleInfo = TableStyleInfo( + name="TableStyleMedium9", + showFirstColumn=False, + showLastColumn=False, + showRowStripes=True, + showColumnStripes=False, + ) + inputs.add_table(inputs_table) + + list_validation = DataValidation( + type="list", formula1='"Low,Medium,High"', allow_blank=True + ) + list_validation.add("H2:H41") + inputs.add_data_validation(list_validation) + decimal_validation = DataValidation( + type="decimal", + operator="between", + formula1="0", + formula2="100000", + allow_blank=False, + ) + decimal_validation.add("B2:G41") + inputs.add_data_validation(decimal_validation) + inputs.conditional_formatting.add( + "B2:H41", + CellIsRule( + operator="greaterThan", + formula=["1000"], + fill=PatternFill("solid", fgColor="FFF2CC"), + ), + ) + inputs.conditional_formatting.add( + "B2:H41", + ColorScaleRule( + start_type="min", + start_color="F8696B", + mid_type="percentile", + mid_value=50, + mid_color="FFEB84", + end_type="max", + end_color="63BE7B", + ), + ) + + schedule.append(["Schedule Metric", *headers[1:]]) + for row_index in range(2, 15): + schedule.cell(row_index, 1, f"Schedule {row_index - 1:02d}") + for column_index in range(2, 9): + column_letter = get_column_letter(column_index) + input_row = row_index + 1 + if row_index == 2: + formula = f"=Inputs!{column_letter}{input_row}" + elif row_index == 3: + formula = f"=SUM({column_letter}2,Inputs!{column_letter}{input_row})" + else: + formula = f"=SUM({column_letter}2:{column_letter}{row_index - 1})" + schedule.cell(row_index, column_index, formula) + schedule.freeze_panes = "B2" + schedule.protection.sheet = True + + summary.append(["Summary Metric", *headers[1:]]) + for row_index in range(2, 12): + summary.cell(row_index, 1, f"Summary {row_index - 1:02d}") + source_row = row_index + 2 + for column_index in range(2, 9): + column_letter = get_column_letter(column_index) + summary.cell( + row_index, column_index, f"=Schedule!{column_letter}{source_row}" + ) + summary.freeze_panes = "B2" + summary.page_setup.orientation = "landscape" + summary.page_setup.fitToWidth = 1 + summary.print_title_rows = "$1:$2" + summary.oddHeader.center.text = "Quarterly Model" + + values = Reference(summary, min_col=2, max_col=8, min_row=1, max_row=11) + categories = Reference(summary, min_col=1, min_row=2, max_row=11) + bar_chart = BarChart() + bar_chart.title = "Quarterly Summary" + bar_chart.add_data(values, titles_from_data=True) + bar_chart.set_categories(categories) + bar_chart.anchor = _anchor("B2", "H12") + summary.add_chart(bar_chart) + + line_chart = LineChart() + line_chart.title = "Quarterly Trend" + line_chart.add_data(values, titles_from_data=True) + line_chart.set_categories(categories) + line_chart.anchor = _anchor("J2", "P12") + summary.add_chart(line_chart) + + workbook.defined_names.add( + DefinedName("CorporateInputs", attr_text="'Inputs'!$B$2:$H$10") + ) + workbook.defined_names.add( + DefinedName("LocalGrowthRate", attr_text="'Inputs'!$B$2", localSheetId=0) + ) + workbook.save(path) + workbook.close() + + +def _inject_custom_xml(path: Path) -> None: + """Inject package parts OpenPyXL intentionally does not preserve on save.""" + with ZipFile(path) as archive: + parts = {name: archive.read(name) for name in archive.namelist()} + + root_rels = ET.fromstring(parts["_rels/.rels"]) + ET.register_namespace("", _RELATIONSHIPS_NS) + relation_tag = f"{{{_RELATIONSHIPS_NS}}}Relationship" + if not any( + relation.get("Type") == f"{_OFFICE_DOCUMENT_REL_NS}/customXml" + for relation in root_rels + ): + existing_ids = {relation.get("Id") for relation in root_rels} + relation_id = "rId1" + suffix = 1 + while relation_id in existing_ids: + suffix += 1 + relation_id = f"rId{suffix}" + ET.SubElement( + root_rels, + relation_tag, + { + "Id": relation_id, + "Type": f"{_OFFICE_DOCUMENT_REL_NS}/customXml", + "Target": "customXml/item1.xml", + }, + ) + parts["_rels/.rels"] = ET.tostring( + root_rels, encoding="utf-8", xml_declaration=True + ) + + content_types = ET.fromstring(parts["[Content_Types].xml"]) + ET.register_namespace("", _CONTENT_TYPES_NS) + override_tag = f"{{{_CONTENT_TYPES_NS}}}Override" + required_override = "/customXml/itemProps1.xml" + if not any(item.get("PartName") == required_override for item in content_types): + ET.SubElement( + content_types, + override_tag, + { + "PartName": required_override, + "ContentType": ( + "application/vnd.openxmlformats-officedocument.customXmlProperties+xml" + ), + }, + ) + parts["[Content_Types].xml"] = ET.tostring( + content_types, encoding="utf-8", xml_declaration=True + ) + + parts["customXml/item1.xml"] = b""" + + openpyxl-targeted-fixture +""" + parts["customXml/itemProps1.xml"] = b""" + + +""" + parts[ + "customXml/_rels/item1.xml.rels" + ] = b""" + + +""" + + core = parts["docProps/core.xml"].decode("utf-8") + core = re.sub( + r"(]*>)[^<]*()", + r"\g<1>2026-01-01T00:00:00Z\g<2>", + core, + ) + parts["docProps/core.xml"] = core.encode("utf-8") + + with ZipFile(path, "w", compression=ZIP_DEFLATED, compresslevel=9) as archive: + for name in sorted(parts): + info = ZipInfo(filename=name, date_time=FIXED_TIMESTAMP) + info.compress_type = ZIP_DEFLATED + archive.writestr(info, parts[name]) + + +def _sha256(data: bytes) -> str: + """Return a SHA-256 digest for fixture package content.""" + return hashlib.sha256(data).hexdigest() + + +def build_fixture() -> Path: + """Build the workbook and manifest, returning the workbook path.""" + FIXTURE_DIR.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile( + suffix=".xlsx", dir=FIXTURE_DIR, delete=False + ) as temporary: + staging_path = Path(temporary.name) + try: + _make_workbook(staging_path) + _inject_custom_xml(staging_path) + staging_path.replace(FIXTURE_PATH) + finally: + staging_path.unlink(missing_ok=True) + + with ZipFile(FIXTURE_PATH) as archive: + part_names = sorted(archive.namelist()) + checksums = {name: _sha256(archive.read(name)) for name in part_names} + manifest = { + "generated_at": GENERATED_AT, + "generator": "openpyxl-structural+customxml-injection", + "parts": part_names, + "checksums": checksums, + "mutation": {"sheet": "Inputs", "cell": "B2", "value": "MUTATED-"}, + "second_mutation": {"sheet": "Inputs", "cell": "C3", "value": 1337}, + } + MANIFEST_PATH.write_text( + json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8" + ) + return FIXTURE_PATH + + +def main() -> None: + """Build the committed mutation fixture.""" + print(build_fixture()) + + +if __name__ == "__main__": + main() diff --git a/scripts/build_tier4_fixtures.py b/scripts/build_tier4_fixtures.py new file mode 100755 index 0000000..4bf7670 --- /dev/null +++ b/scripts/build_tier4_fixtures.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 +"""Build Tier-4 structural fixtures: sheet_protection, page_setup, chart_anchor. + +No Excel application is involved: workbooks are constructed with openpyxl +through OpenpyxlAdapter's Tier-4 methods, and every manifest expectation is +recorded from the post-save readback, so expectations always equal roundtrip +reality. + +Outputs under (default: fixtures/excel): + tier4/20_sheet_protection.xlsx + tier4/21_page_setup.xlsx + tier4/22_chart_anchor.xlsx + tier4_manifest_fragment.json (to be merged into manifest.json) +""" + +from __future__ import annotations + +import json +import sys +from datetime import UTC, datetime +from pathlib import Path +from typing import Any + +from excelbench.harness.adapters.openpyxl_adapter import OpenpyxlAdapter +from excelbench.models import CellType, CellValue + +REPO_ROOT = Path(__file__).resolve().parent.parent +DEFAULT_FIXTURES_ROOT = REPO_ROOT / "fixtures" / "excel" +TIER4_DIR = "tier4" +GENERATOR = "openpyxl-structural" +GENERATOR_VERSION = "0.1.0" + +JSONDict = dict[str, Any] + +PROTECTION_CASES: list[JSONDict] = [ + { + "sheet": "sheet_protection_basic", + "id": "prot_basic", + "label": "Protection: basic (OOXML defaults)", + "importance": "basic", + "settings": {"protected": True}, + }, + { + "sheet": "sheet_protection_password", + "id": "prot_password", + "label": "Protection: with password hash", + "importance": "basic", + "settings": {"protected": True, "password": "bench-secret"}, + }, + { + "sheet": "sheet_protection_granular", + "id": "prot_granular", + "label": "Protection: granular attribute flags", + "importance": "edge", + "settings": { + "protected": True, + "format_cells": False, + "insert_rows": True, + "select_locked_cells": True, + "sort": False, + "auto_filter": True, + }, + }, +] + +PAGE_SETUP_CASES: list[JSONDict] = [ + { + "sheet": "page_setup_landscape", + "id": "page_setup_landscape", + "label": "Page setup: landscape + fit-to-width", + "importance": "basic", + "settings": {"orientation": "landscape", "fit_to_width": 1}, + }, + { + "sheet": "page_setup_scale", + "id": "page_setup_scale", + "label": "Page setup: portrait at 75% scale", + "importance": "basic", + "settings": {"orientation": "portrait", "scale": 75}, + }, + { + "sheet": "page_setup_titles", + "id": "page_setup_titles", + "label": "Page setup: print titles + header/footer", + "importance": "edge", + "settings": { + "print_title_rows": "$1:$2", + "header_center": "ExcelBench Report", + "footer_center": "Page &P", + }, + }, +] + +CHART_DATA_NUMBERS = [12, 25, 18, 31, 22, 40, 29] # E2:E8 +CHART_DATA_LABELS = ["Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "Q7"] # F2:F8 + +CHART_CASES: list[JSONDict] = [ + { + "id": "chart_bar", + "label": "Chart: bar with twoCell anchor", + "importance": "basic", + "chart": { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8", + }, + }, + { + "id": "chart_line", + "label": "Chart: line with twoCell anchor", + "importance": "edge", + "chart": { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8", + }, + }, +] + + +def build_sheet_protection(adapter: OpenpyxlAdapter, out_dir: Path) -> JSONDict: + """Build 20_sheet_protection.xlsx and return its manifest entry.""" + path = out_dir / "20_sheet_protection.xlsx" + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "sheet_protection") + for case in PROTECTION_CASES: + adapter.add_sheet(workbook, case["sheet"]) + for case in PROTECTION_CASES: + adapter.set_sheet_protection(workbook, case["sheet"], case["settings"]) + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + test_cases = [] + for case in PROTECTION_CASES: + expected = dict(adapter.read_sheet_protection(reopened, case["sheet"])) + password = case["settings"].get("password") + if password is not None: + expected["password"] = password + test_cases.append(_test_case(case, {"protection": expected})) + finally: + adapter.close_workbook(reopened) + return _manifest_entry(path.name, "sheet_protection", test_cases) + + +def build_page_setup(adapter: OpenpyxlAdapter, out_dir: Path) -> JSONDict: + """Build 21_page_setup.xlsx and return its manifest entry.""" + path = out_dir / "21_page_setup.xlsx" + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "page_setup") + for case in PAGE_SETUP_CASES: + adapter.add_sheet(workbook, case["sheet"]) + for case in PAGE_SETUP_CASES: + adapter.set_page_setup(workbook, case["sheet"], case["settings"]) + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + test_cases = [ + _test_case( + case, {"page_setup": adapter.read_page_setup(reopened, case["sheet"])} + ) + for case in PAGE_SETUP_CASES + ] + finally: + adapter.close_workbook(reopened) + return _manifest_entry(path.name, "page_setup", test_cases) + + +def build_chart_anchor(adapter: OpenpyxlAdapter, out_dir: Path) -> JSONDict: + """Build 22_chart_anchor.xlsx and return its manifest entry.""" + path = out_dir / "22_chart_anchor.xlsx" + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "chart_anchor") + for offset, value in enumerate(CHART_DATA_NUMBERS): + adapter.write_cell_value( + workbook, + "chart_anchor", + f"E{2 + offset}", + CellValue(type=CellType.NUMBER, value=value), + ) + for offset, label in enumerate(CHART_DATA_LABELS): + adapter.write_cell_value( + workbook, + "chart_anchor", + f"F{2 + offset}", + CellValue(type=CellType.STRING, value=label), + ) + for case in CHART_CASES: + adapter.add_chart_with_anchor(workbook, "chart_anchor", case["chart"]) + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + charts_by_from = { + chart["from"]: chart + for chart in adapter.read_chart_anchors(reopened, "chart_anchor") + } + finally: + adapter.close_workbook(reopened) + + test_cases = [] + for case in CHART_CASES: + spec = case["chart"] + readback = charts_by_from.get(spec["from"]) + if readback is None: + raise RuntimeError(f"chart anchor readback missing for {spec['from']}") + expected = { + **readback, + "data_ref": spec["data_ref"], + "categories_ref": spec["categories_ref"], + } + test_cases.append(_test_case(case, {"charts": [expected]})) + return _manifest_entry(path.name, "chart_anchor", test_cases) + + +def _test_case(case: JSONDict, expected: JSONDict) -> JSONDict: + entry: JSONDict = { + "id": case["id"], + "label": case["label"], + "row": 2, + } + if case.get("sheet"): + entry["sheet"] = case["sheet"] + entry["expected"] = expected + entry["importance"] = case["importance"] + return entry + + +def _manifest_entry( + filename: str, feature: str, test_cases: list[JSONDict] +) -> JSONDict: + return { + "path": f"{TIER4_DIR}/{filename}", + "feature": feature, + "tier": 4, + "file_format": "xlsx", + "test_cases": test_cases, + } + + +def build_all(fixtures_root: Path = DEFAULT_FIXTURES_ROOT) -> Path: + """Build all Tier-4 fixtures plus the manifest fragment. + + Returns the path to the written fragment. + """ + out_dir = fixtures_root / TIER4_DIR + out_dir.mkdir(parents=True, exist_ok=True) + adapter = OpenpyxlAdapter() + entries = [ + build_sheet_protection(adapter, out_dir), + build_page_setup(adapter, out_dir), + build_chart_anchor(adapter, out_dir), + ] + fragment: JSONDict = { + "generated_at": datetime.now(UTC).isoformat(), + "excel_version": "none", + "generator_version": GENERATOR_VERSION, + "generator": GENERATOR, + "file_format": "xlsx", + "files": entries, + } + fragment_path = fixtures_root / "tier4_manifest_fragment.json" + with open(fragment_path, "w") as f: + json.dump(fragment, f, indent=2) + f.write("\n") + return fragment_path + + +def main(argv: list[str] | None = None) -> int: + args = sys.argv[1:] if argv is None else argv + fixtures_root = Path(args[0]).resolve() if args else DEFAULT_FIXTURES_ROOT + fragment_path = build_all(fixtures_root) + print(f"Tier-4 fixtures written to {fixtures_root / TIER4_DIR}") + print(f"Manifest fragment: {fragment_path}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/excelbench/cli.py b/src/excelbench/cli.py index 4c8292b..954be37 100644 --- a/src/excelbench/cli.py +++ b/src/excelbench/cli.py @@ -20,7 +20,7 @@ XLS_PROFILE_DEFAULT_TEST_DIR = Path("fixtures/excel_xls") XLSX_PROFILE_DEFAULT_TEST_DIR = Path("test_files") PERF_XLSX_PROFILE_DEFAULT_TEST_DIR = Path("fixtures/excel") -CROSS_LANGUAGE_ADAPTER_NAMES = ("apache-poi", "excelize") +CROSS_LANGUAGE_ADAPTER_NAMES = ("apache-poi", "excelize", "zavora-xlsx") @app.command() @@ -123,7 +123,10 @@ def benchmark( console.print("[red]Error: profile must be one of: xlsx, xls[/red]") raise typer.Exit(1) - if profile == "xls" and test_dir.resolve() == XLSX_PROFILE_DEFAULT_TEST_DIR.resolve(): + if ( + profile == "xls" + and test_dir.resolve() == XLSX_PROFILE_DEFAULT_TEST_DIR.resolve() + ): test_dir = XLS_PROFILE_DEFAULT_TEST_DIR # These command functions are sometimes invoked directly from tests. @@ -162,7 +165,9 @@ def benchmark( console.print() try: - results = run_benchmark(test_dir, adapters=selected, features=features, profile=profile) + results = run_benchmark( + test_dir, adapters=selected, features=features, profile=profile + ) if append_results: import json @@ -303,7 +308,10 @@ def perf( ) raise typer.Exit(1) - if profile == "xls" and test_dir.resolve() == PERF_XLSX_PROFILE_DEFAULT_TEST_DIR.resolve(): + if ( + profile == "xls" + and test_dir.resolve() == PERF_XLSX_PROFILE_DEFAULT_TEST_DIR.resolve() + ): test_dir = XLS_PROFILE_DEFAULT_TEST_DIR available = get_all_adapters() @@ -348,7 +356,9 @@ def perf( ) render_perf_results(perf_results, output_dir) - console.print(f"[green]✓ Performance results written to {output_dir}/perf[/green]") + console.print( + f"[green]✓ Performance results written to {output_dir}/perf[/green]" + ) console.print(f" - {output_dir}/perf/results.json") console.print(f" - {output_dir}/perf/README.md") console.print(f" - {output_dir}/perf/matrix.csv") @@ -390,7 +400,9 @@ def perf( ] -def _resolve_shape_features(*, types_arg: str, rows: int) -> tuple[list[str], list[str], list[str]]: +def _resolve_shape_features( + *, types_arg: str, rows: int +) -> tuple[list[str], list[str], list[str]]: """Translate --types and --rows into (read_features, write_features, tier_labels). Tiers are chosen as every label whose canonical cell-count <= ``rows``, so @@ -413,7 +425,9 @@ def _resolve_shape_features(*, types_arg: str, rows: int) -> tuple[list[str], li tier_labels = [label for label, cap in _DATA_SHAPE_TIER_CAPS if cap <= rows] if not tier_labels: - raise ValueError(f"--rows {rows} is below the smallest tier (1000); pick at least 1000.") + raise ValueError( + f"--rows {rows} is below the smallest tier (1000); pick at least 1000." + ) read_features: list[str] = [] write_features: list[str] = [] @@ -521,7 +535,9 @@ def _resolve_file_shape_features( for label, total_cells in _FILE_SHAPE_LABELS: if total_cells > rows: continue - category = next((c for c in _FILE_SHAPE_CATEGORIES if label.startswith(c)), None) + category = next( + (c for c in _FILE_SHAPE_CATEGORIES if label.startswith(c)), None + ) if category in wanted_cats: selected.append(label) @@ -579,7 +595,9 @@ def _file_shape_fixtures_stale( and isinstance(f.get("feature"), str) and f["feature"].startswith("file_shape_") and ( - "_1m" in f["feature"] or "_100x10k_" in f["feature"] or "_1000x1k_" in f["feature"] + "_1m" in f["feature"] + or "_100x10k_" in f["feature"] + or "_1000x1k_" in f["feature"] ) for f in files ): @@ -689,10 +707,14 @@ def perf_shape( needs_1m = "1m" in tier_labels manifest_path = fixtures / "manifest.json" generator_script = ( - Path(__file__).resolve().parents[2] / "scripts" / "generate_throughput_fixtures.py" + Path(__file__).resolve().parents[2] + / "scripts" + / "generate_throughput_fixtures.py" ) - if regenerate or _shape_fixtures_stale(manifest_path, generator_script, needs_1m=needs_1m): + if regenerate or _shape_fixtures_stale( + manifest_path, generator_script, needs_1m=needs_1m + ): gen_cmd = [ sys.executable, str(generator_script), @@ -875,10 +897,14 @@ def perf_file_shape( ) manifest_path = fixtures / "manifest.json" generator_script = ( - Path(__file__).resolve().parents[2] / "scripts" / "generate_throughput_fixtures.py" + Path(__file__).resolve().parents[2] + / "scripts" + / "generate_throughput_fixtures.py" ) - if regenerate or _file_shape_fixtures_stale(manifest_path, generator_script, needs_1m=needs_1m): + if regenerate or _file_shape_fixtures_stale( + manifest_path, generator_script, needs_1m=needs_1m + ): gen_cmd = [ sys.executable, str(generator_script), @@ -888,7 +914,9 @@ def perf_file_shape( ] if needs_1m: gen_cmd.append("--include-1m") - console.print(f"[bold]Generating file-shape fixtures...[/bold] {' '.join(gen_cmd)}") + console.print( + f"[bold]Generating file-shape fixtures...[/bold] {' '.join(gen_cmd)}" + ) try: subprocess.run(gen_cmd, check=True) except subprocess.CalledProcessError as e: @@ -986,7 +1014,9 @@ def generate_xls_command( table.add_column("Feature", style="magenta") table.add_column("Test Cases", justify="right", style="green") for test_file in manifest.files: - table.add_row(test_file.path, test_file.feature, str(len(test_file.test_cases))) + table.add_row( + test_file.path, test_file.feature, str(len(test_file.test_cases)) + ) console.print(table) except Exception as e: console.print(f"[red]Error: {e}[/red]") @@ -1092,7 +1122,9 @@ def roundtrip_context( "-a", help="Run only specified adapter(s) by name. Repeatable.", ), - cycles: int = typer.Option(2, "--cycles", min=1, help="Number of open/save cycles."), + cycles: int = typer.Option( + 2, "--cycles", min=1, help="Number of open/save cycles." + ), ) -> None: """Measure semantic drift after repeated workbook open/save cycles.""" from excelbench.harness.adapters import get_all_adapters @@ -1103,13 +1135,19 @@ def roundtrip_context( selected = [available[name] for name in selected_names if name in available] missing = [name for name in selected_names if name not in available] if missing: - console.print(f"[yellow]Skipping unavailable adapters: {', '.join(missing)}[/yellow]") + console.print( + f"[yellow]Skipping unavailable adapters: {', '.join(missing)}[/yellow]" + ) if not selected: console.print("[red]Error: No selected adapters are available.[/red]") raise typer.Exit(1) - results = run_roundtrip_context(test_dir, output_dir, adapters=selected, cycles=cycles) - failures = [result for result in results if not result.passed and not result.skipped] + results = run_roundtrip_context( + test_dir, output_dir, adapters=selected, cycles=cycles + ) + failures = [ + result for result in results if not result.passed and not result.skipped + ] console.print(f"[green]✓ Roundtrip context written to {output_dir}[/green]") console.print(f" - {output_dir}/roundtrip.json") console.print(f" - {output_dir}/ROUNDTRIP.md") @@ -1135,7 +1173,9 @@ def compatibility_context( from excelbench.harness.compat_cases import run_compatibility_context payload = run_compatibility_context(output_dir, adapter_names=adapters) - failures = [row for row in payload["results"] if not row["passed"] and not row["skipped"]] + failures = [ + row for row in payload["results"] if not row["passed"] and not row["skipped"] + ] console.print(f"[green]✓ Compatibility context written to {output_dir}[/green]") console.print(f" - {output_dir}/compatibility.json") console.print(f" - {output_dir}/COMPATIBILITY.md") @@ -1160,7 +1200,9 @@ def cross_language_chart_context( from excelbench.harness.artifact_context import run_chart_context payload = run_chart_context(fixture_dir, output_dir) - failures = [row for row in payload["results"] if not row["passed"] and not row["skipped"]] + failures = [ + row for row in payload["results"] if not row["passed"] and not row["skipped"] + ] console.print(f"[green]✓ Chart context written to {output_dir}[/green]") console.print(f" - {output_dir}/results.json") console.print(f" - {output_dir}/README.md") @@ -1190,8 +1232,12 @@ def macro_context( """Validate macro package preservation evidence.""" from excelbench.harness.artifact_context import run_macro_context - payload = run_macro_context(test_dir, output_dir, preserve_with_wolfxl=preserve_with_wolfxl) - failures = [row for row in payload["results"] if not row["passed"] and not row["skipped"]] + payload = run_macro_context( + test_dir, output_dir, preserve_with_wolfxl=preserve_with_wolfxl + ) + failures = [ + row for row in payload["results"] if not row["passed"] and not row["skipped"] + ] console.print(f"[green]✓ Macro context written to {output_dir}[/green]") console.print(f" - {output_dir}/results.json") console.print(f" - {output_dir}/README.md") @@ -1223,7 +1269,9 @@ def cross_language_context( from excelbench.results import render_results available = {adapter.name: adapter for adapter in get_all_adapters()} - selected = [available[name] for name in CROSS_LANGUAGE_ADAPTER_NAMES if name in available] + selected = [ + available[name] for name in CROSS_LANGUAGE_ADAPTER_NAMES if name in available + ] if not selected: console.print( @@ -1243,7 +1291,9 @@ def cross_language_context( render_results(results, output_dir) _write_cross_language_index(output_dir, [a.name for a in selected]) console.print() - console.print(f"[green]✓ Cross-language context results written to {output_dir}[/green]") + console.print( + f"[green]✓ Cross-language context results written to {output_dir}[/green]" + ) console.print(f" - {output_dir}/results.json") console.print(f" - {output_dir}/README.md") console.print(f" - {output_dir}/matrix.csv") @@ -1280,10 +1330,14 @@ def cross_language_pivot_context( output_dir.mkdir(parents=True, exist_ok=True) results = _collect_cross_language_pivot_context(fixture_path, output_dir) - (output_dir / "results.json").write_text(json.dumps(results, indent=2), encoding="utf-8") + (output_dir / "results.json").write_text( + json.dumps(results, indent=2), encoding="utf-8" + ) _write_cross_language_pivot_readme(output_dir, results) _write_cross_language_pivot_context_note(output_dir) - console.print(f"[green]✓ Cross-language pivot context written to {output_dir}[/green]") + console.print( + f"[green]✓ Cross-language pivot context written to {output_dir}[/green]" + ) console.print(f" - {output_dir}/results.json") console.print(f" - {output_dir}/README.md") console.print(f" - {output_dir}/CONTEXT.md") @@ -1348,7 +1402,9 @@ def _results_from_json(data: dict[str, Any]) -> "BenchmarkResults": severity=DiagnosticSeverity(d["severity"]), location=DiagnosticLocation( feature=d["location"]["feature"], - operation=OperationType(d["location"]["operation"]), + operation=OperationType( + d["location"]["operation"] + ), test_case_id=d["location"].get("test_case_id"), sheet=d["location"].get("sheet"), cell=d["location"].get("cell"), @@ -1379,7 +1435,11 @@ def _results_from_json(data: dict[str, Any]) -> "BenchmarkResults": actual=tc["actual"], notes=tc.get("notes"), diagnostics=[], - importance=(Importance(tc["importance"]) if tc.get("importance") else None), + importance=( + Importance(tc["importance"]) + if tc.get("importance") + else None + ), label=tc.get("label"), ) ) @@ -1468,7 +1528,9 @@ def _write_cross_language_index(output_dir: Path, adapters: list[str]) -> None: (output_dir / "CONTEXT.md").write_text(content) -def _collect_cross_language_pivot_context(fixture_path: Path, output_dir: Path) -> dict[str, Any]: +def _collect_cross_language_pivot_context( + fixture_path: Path, output_dir: Path +) -> dict[str, Any]: import platform as _platform from datetime import UTC, datetime from zipfile import ZipFile @@ -1515,7 +1577,9 @@ def _collect_cross_language_pivot_context(fixture_path: Path, output_dir: Path) ) helper_info["fixture_metadata"] = res.payload if res.passed: - helper_info["fixture_read_detects_pivot"] = _helper_detects_pivot(name, res.payload) + helper_info["fixture_read_detects_pivot"] = _helper_detects_pivot( + name, res.payload + ) else: helper_info["fixture_error"] = ( res.payload.get("message") or res.stderr or res.stdout @@ -1552,7 +1616,9 @@ def _helper_detects_pivot(helper_name: str, payload: dict[str, Any]) -> bool: sheets = payload.get("sheets") or [] return any(int(sheet.get("pivots", 0)) > 0 for sheet in sheets) counts = payload.get("counts") or {} - return any("pivot" in key.lower() and int(value) > 0 for key, value in counts.items()) + return any( + "pivot" in key.lower() and int(value) > 0 for key, value in counts.items() + ) def _run_excelize_pivot_probe(output_path: Path) -> dict[str, Any]: @@ -1617,7 +1683,9 @@ def _run_excelize_pivot_probe(output_path: Path) -> dict[str, Any]: pivot_parts: list[str] = [] with ZipFile(output_path) as zf: pivot_parts = sorted( - name for name in zf.namelist() if "pivot" in name.lower() or "cache" in name.lower() + name + for name in zf.namelist() + if "pivot" in name.lower() or "cache" in name.lower() ) verifier = OpenpyxlAdapter() wb = verifier.open_workbook(output_path) @@ -1641,7 +1709,9 @@ def _pivot_coord_to_cell(row: int, col: int) -> str: return f"{letters}{row}" -def _write_cross_language_pivot_readme(output_dir: Path, results: dict[str, Any]) -> None: +def _write_cross_language_pivot_readme( + output_dir: Path, results: dict[str, Any] +) -> None: import json fixture = results["fixture"] @@ -1664,7 +1734,8 @@ def _write_cross_language_pivot_readme(output_dir: Path, results: dict[str, Any] ] if fixture_parts: lines.extend( - ["- Fixture pivot-related parts:"] + [f" - `{part}`" for part in fixture_parts] + ["- Fixture pivot-related parts:"] + + [f" - `{part}`" for part in fixture_parts] ) else: lines.append("- Fixture pivot-related parts: none detected") @@ -1683,7 +1754,9 @@ def _write_cross_language_pivot_readme(output_dir: Path, results: dict[str, Any] "| Tool | Pivot write support | Evidence |", "|---|---:|---|", _pivot_probe_row("apache-poi", apache_probe, ""), - _pivot_probe_row("excelize", excelize_probe, "OOXML parts + openpyxl readback"), + _pivot_probe_row( + "excelize", excelize_probe, "OOXML parts + openpyxl readback" + ), ] ) if excelize_probe.get("supported"): @@ -1695,7 +1768,10 @@ def _write_cross_language_pivot_readme(output_dir: Path, results: dict[str, Any] f"- Output workbook: `{excelize_probe['output_path']}`", "- Pivot-related OOXML parts:", ] - + [f" - `{part}`" for part in excelize_probe.get("pivot_related_parts", [])] + + [ + f" - `{part}`" + for part in excelize_probe.get("pivot_related_parts", []) + ] + [ "- Openpyxl readback:", "```json\n" @@ -1726,9 +1802,13 @@ def _pivot_helper_row(helper_name: str, helpers: dict[str, Any], notes: str) -> return f"| {helper_name} | {available} | {detects} | {notes} |" -def _pivot_probe_row(tool_name: str, probe: dict[str, Any], success_evidence: str) -> str: +def _pivot_probe_row( + tool_name: str, probe: dict[str, Any], success_evidence: str +) -> str: supported = "Yes" if probe.get("supported") else "No" - evidence = success_evidence if probe.get("supported") else str(probe.get("reason", "")) + evidence = ( + success_evidence if probe.get("supported") else str(probe.get("reason", "")) + ) return f"| {tool_name} | {supported} | {evidence} |" @@ -1818,7 +1898,9 @@ def heatmap( for p in paths: console.print(f" [green]✓[/green] {p}") if not paths: - console.print("[yellow]No scored results found — nothing to render.[/yellow]") + console.print( + "[yellow]No scored results found — nothing to render.[/yellow]" + ) except Exception as e: console.print(f"[red]Error: {e}[/red]") raise typer.Exit(1) @@ -1899,7 +1981,11 @@ def html_dashboard( try: perf = perf_path if perf_path.exists() else None sdir = scatter_dir if scatter_dir.exists() else None - mem = memory_path if isinstance(memory_path, Path) and memory_path.exists() else None + mem = ( + memory_path + if isinstance(memory_path, Path) and memory_path.exists() + else None + ) render_html_dashboard(fidelity_path, perf, output_path, sdir, memory_json=mem) console.print(f" [green]✓[/green] {output_path}") except Exception as e: @@ -1952,6 +2038,110 @@ def scatter( raise typer.Exit(1) +@app.command() +def mutation( + template: Path = typer.Option( + Path("fixtures/mutation/template_corporate_model.xlsx"), + "--template", + help="Corporate-model template workbook to mutate.", + ), + output_dir: Path = typer.Option( + Path("results/mutation"), + "--output", + "-o", + help="Directory to save mutation-suite results.", + ), + repeats: int = typer.Option( + 3, + "--repeats", + help="Measured mutation runs per engine (median reported).", + ), +) -> None: + """Run the surgical template-mutation suite. + + Each engine mutates two cells in a complex corporate template; the suite + measures wall time, peak RSS, and a package-preservation score against the + original template. + """ + from excelbench.harness.mutation import run_mutation_suite + + if not template.exists(): + console.print(f"[red]Error: template not found at {template}[/red]") + raise typer.Exit(1) + console.print("[bold]Running template-mutation suite...[/bold]") + console.print(f" Template: {template}") + console.print(f" Output: {output_dir}") + console.print() + + try: + results = run_mutation_suite(template, output_dir, repeats=repeats) + from excelbench.results.mutation_renderer import render_mutation_report + + render_mutation_report(results, output_dir) + for name, engine in results["engines"].items(): + console.print( + f" {name}: {engine['status']}, " + f"{engine['wall_ms_median']}ms, preservation {engine['preservation_score']}" + ) + console.print() + console.print(f"[green]✓ Mutation results written to {output_dir}[/green]") + except Exception as e: + console.print(f"[red]Error: {e}[/red]") + raise typer.Exit(1) + + +@app.command() +def calc( + fixture: Path = typer.Option( + Path("fixtures/calc/financial_model.xlsx"), + "--fixture", + help="Cache-free formula fixture workbook.", + ), + expected: Path = typer.Option( + Path("fixtures/calc/expected_values.json"), + "--expected", + help="Oracle expected-values JSON for the fixture.", + ), + output_dir: Path = typer.Option( + Path("results/calc"), + "--output", + "-o", + help="Directory to save calculation-tier results.", + ), +) -> None: + """Run the formula-recalculation tier against the oracle fixture. + + The fixture ships formulas without cached values, so every scored value + must be produced by the engine itself. + """ + from excelbench.harness.calc import run_calc_suite + + if not fixture.exists(): + console.print(f"[red]Error: fixture not found at {fixture}[/red]") + raise typer.Exit(1) + if not expected.exists(): + console.print(f"[red]Error: expected values not found at {expected}[/red]") + raise typer.Exit(1) + + console.print("[bold]Running formula-recalculation tier...[/bold]") + console.print(f" Fixture: {fixture}") + console.print(f" Oracle: {expected}") + console.print(f" Output: {output_dir}") + console.print() + + try: + results = run_calc_suite(fixture, expected, output_dir) + for name, engine in results["engines"].items(): + console.print( + f" {name}: {engine['status']}, {engine['matched']}/{engine['total']}" + ) + console.print() + console.print(f"[green]✓ Calculation results written to {output_dir}[/green]") + except Exception as e: + console.print(f"[red]Error: {e}[/red]") + raise typer.Exit(1) + + def show_summary(results: "BenchmarkResults") -> None: """Show a quick summary table of results.""" from excelbench.results.renderer import score_emoji diff --git a/src/excelbench/harness/adapters/__init__.py b/src/excelbench/harness/adapters/__init__.py index 196364c..eb09176 100644 --- a/src/excelbench/harness/adapters/__init__.py +++ b/src/excelbench/harness/adapters/__init__.py @@ -2,7 +2,11 @@ from typing import TypeAlias -from excelbench.harness.adapters.base import ExcelAdapter, ReadOnlyAdapter, WriteOnlyAdapter +from excelbench.harness.adapters.base import ( + ExcelAdapter, + ReadOnlyAdapter, + WriteOnlyAdapter, +) from excelbench.harness.adapters.openpyxl_adapter import OpenpyxlAdapter AdapterClass: TypeAlias = type[ExcelAdapter] @@ -16,6 +20,7 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: return True return bool(is_available()) + try: from excelbench.harness.adapters.xlsxwriter_adapter import ( XlsxwriterAdapter as _XlsxwriterAdapter, @@ -25,7 +30,9 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: else: XlsxwriterAdapter = _XlsxwriterAdapter try: - from excelbench.harness.adapters.calamine_adapter import CalamineAdapter as _CalamineAdapter + from excelbench.harness.adapters.calamine_adapter import ( + CalamineAdapter as _CalamineAdapter, + ) except ImportError: CalamineAdapter: AdapterClass | None = None else: @@ -75,14 +82,18 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: WolfxlAdapter = _WolfxlAdapter try: - from excelbench.harness.adapters.pyumya_adapter import PyumyaAdapter as _PyumyaAdapter + from excelbench.harness.adapters.pyumya_adapter import ( + PyumyaAdapter as _PyumyaAdapter, + ) except ImportError: PyumyaAdapter: AdapterClass | None = None else: PyumyaAdapter = _PyumyaAdapter try: - from excelbench.harness.adapters.pylightxl_adapter import PylightxlAdapter as _PylightxlAdapter + from excelbench.harness.adapters.pylightxl_adapter import ( + PylightxlAdapter as _PylightxlAdapter, + ) except ImportError: PylightxlAdapter: AdapterClass | None = None else: @@ -94,7 +105,9 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: else: XlrdAdapter = _XlrdAdapter try: - from excelbench.harness.adapters.pyexcel_adapter import PyexcelAdapter as _PyexcelAdapter + from excelbench.harness.adapters.pyexcel_adapter import ( + PyexcelAdapter as _PyexcelAdapter, + ) except ImportError: PyexcelAdapter: AdapterClass | None = None else: @@ -106,7 +119,9 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: else: XlwtAdapter = _XlwtAdapter try: - from excelbench.harness.adapters.pandas_adapter import PandasAdapter as _PandasAdapter + from excelbench.harness.adapters.pandas_adapter import ( + PandasAdapter as _PandasAdapter, + ) except ImportError: PandasAdapter: AdapterClass | None = None else: @@ -129,13 +144,17 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: else: OpenpyxlReadonlyAdapter = _OpenpyxlReadonlyAdapter try: - from excelbench.harness.adapters.polars_adapter import PolarsAdapter as _PolarsAdapter + from excelbench.harness.adapters.polars_adapter import ( + PolarsAdapter as _PolarsAdapter, + ) except ImportError: PolarsAdapter: AdapterClass | None = None else: PolarsAdapter = _PolarsAdapter try: - from excelbench.harness.adapters.tablib_adapter import TablibAdapter as _TablibAdapter + from excelbench.harness.adapters.tablib_adapter import ( + TablibAdapter as _TablibAdapter, + ) except ImportError: TablibAdapter: AdapterClass | None = None else: @@ -151,18 +170,39 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: ExcelOracleAdapter = _ExcelOracleAdapter try: - from excelbench.harness.adapters.apache_poi_adapter import ApachePoiAdapter as _ApachePoiAdapter + from excelbench.harness.adapters.apache_poi_adapter import ( + ApachePoiAdapter as _ApachePoiAdapter, + ) except ImportError: ApachePoiAdapter: AdapterClass | None = None else: ApachePoiAdapter = _ApachePoiAdapter try: - from excelbench.harness.adapters.excelize_adapter import ExcelizeAdapter as _ExcelizeAdapter + from excelbench.harness.adapters.excelize_adapter import ( + ExcelizeAdapter as _ExcelizeAdapter, + ) except ImportError: ExcelizeAdapter: AdapterClass | None = None else: ExcelizeAdapter = _ExcelizeAdapter +try: + from excelbench.harness.adapters.aspose_cells_foss_adapter import ( + AsposeCellsFossAdapter as _AsposeCellsFossAdapter, + ) +except ImportError: + AsposeCellsFossAdapter: AdapterClass | None = None +else: + AsposeCellsFossAdapter = _AsposeCellsFossAdapter +try: + from excelbench.harness.adapters.zavora_adapter import ( + ZavoraAdapter as _ZavoraAdapter, + ) +except ImportError: + ZavoraAdapter: AdapterClass | None = None +else: + ZavoraAdapter = _ZavoraAdapter + __all__ = [ "ExcelAdapter", @@ -202,6 +242,8 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: __all__.append("XlsxwriterConstmemAdapter") if OpenpyxlReadonlyAdapter is not None: __all__.append("OpenpyxlReadonlyAdapter") +if AsposeCellsFossAdapter is not None: + __all__.append("AsposeCellsFossAdapter") if PolarsAdapter is not None: __all__.append("PolarsAdapter") if TablibAdapter is not None: @@ -210,6 +252,8 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: __all__.append("ApachePoiAdapter") if ExcelizeAdapter is not None: __all__.append("ExcelizeAdapter") +if ZavoraAdapter is not None: + __all__.append("ZavoraAdapter") def get_all_adapters() -> list[ExcelAdapter]: @@ -219,6 +263,8 @@ def get_all_adapters() -> list[ExcelAdapter]: adapters.append(XlsxwriterAdapter()) if CalamineAdapter is not None: adapters.append(CalamineAdapter()) + if AsposeCellsFossAdapter is not None: + adapters.append(AsposeCellsFossAdapter()) if RustCalamineAdapter is not None: adapters.append(RustCalamineAdapter()) # RustCalamineStyledAdapter is an internal WolfXL backend, not a standalone @@ -253,4 +299,6 @@ def get_all_adapters() -> list[ExcelAdapter]: adapters.append(ApachePoiAdapter()) if ExcelizeAdapter is not None and _is_available_adapter(ExcelizeAdapter): adapters.append(ExcelizeAdapter()) + if ZavoraAdapter is not None and _is_available_adapter(ZavoraAdapter): + adapters.append(ZavoraAdapter()) return adapters diff --git a/src/excelbench/harness/adapters/aspose_cells_foss_adapter.py b/src/excelbench/harness/adapters/aspose_cells_foss_adapter.py new file mode 100644 index 0000000..547bffb --- /dev/null +++ b/src/excelbench/harness/adapters/aspose_cells_foss_adapter.py @@ -0,0 +1,867 @@ +"""Adapter for the :mod:`aspose.cells_foss` library.""" + +from __future__ import annotations + +from datetime import date, datetime +from pathlib import Path +from typing import Any + +try: + import aspose.cells_foss as aspose + from aspose.cells_foss.data_validation import ( + DataValidationOperator, + DataValidationType, + ) + from aspose.cells_foss.workbook_properties import DefinedName +except ImportError as exc: # pragma: no cover - exercised by the adapter registry. + raise ImportError( + "AsposeCellsFossAdapter requires the optional 'aspose-cells-foss' package." + ) from exc + +from excelbench.harness.adapters.base import ExcelAdapter +from excelbench.models import ( + BorderEdge, + BorderInfo, + BorderStyle, + CellFormat, + CellType, + CellValue, + LibraryInfo, +) + +JSONDict = dict[str, Any] + +_ERROR_FORMULA_MAP = { + "=1/0": "#DIV/0!", + "=NA()": "#N/A", + '="text"+1': "#VALUE!", + "=#REF!": "#REF!", + "=_undefined_name_": "#NAME?", + "=SQRT(-1)": "#NUM!", + "=A1:A2 B1:B2": "#NULL!", +} +_ERROR_VALUE_FORMULA_MAP = {value: key for key, value in _ERROR_FORMULA_MAP.items()} + + +_VALIDATION_TYPES = { + "none": DataValidationType.NONE, + "whole": DataValidationType.WHOLE_NUMBER, + "wholeNumber": DataValidationType.WHOLE_NUMBER, + "decimal": DataValidationType.DECIMAL, + "list": DataValidationType.LIST, + "date": DataValidationType.DATE, + "time": DataValidationType.TIME, + "textLength": DataValidationType.TEXT_LENGTH, + "text_length": DataValidationType.TEXT_LENGTH, + "custom": DataValidationType.CUSTOM, +} +_VALIDATION_TYPE_NAMES = { + DataValidationType.NONE: "none", + DataValidationType.WHOLE_NUMBER: "whole", + DataValidationType.DECIMAL: "decimal", + DataValidationType.LIST: "list", + DataValidationType.DATE: "date", + DataValidationType.TIME: "time", + DataValidationType.TEXT_LENGTH: "textLength", + DataValidationType.CUSTOM: "custom", +} +_VALIDATION_OPERATORS = { + "between": DataValidationOperator.BETWEEN, + "notBetween": DataValidationOperator.NOT_BETWEEN, + "equal": DataValidationOperator.EQUAL, + "notEqual": DataValidationOperator.NOT_EQUAL, + "greaterThan": DataValidationOperator.GREATER_THAN, + "lessThan": DataValidationOperator.LESS_THAN, + "greaterThanOrEqual": DataValidationOperator.GREATER_THAN_OR_EQUAL, + "lessThanOrEqual": DataValidationOperator.LESS_THAN_OR_EQUAL, +} +_VALIDATION_OPERATOR_NAMES = { + value: key for key, value in _VALIDATION_OPERATORS.items() +} + + +def _color_to_hex(value: Any) -> str | None: + """Normalize the library's RGB/ARGB colors to the benchmark's #RRGGBB form.""" + if not isinstance(value, str): + return None + raw = value.lstrip("#").upper() + if len(raw) == 8: + raw = raw[2:] + if len(raw) != 6 or any(char not in "0123456789ABCDEF" for char in raw): + return None + return f"#{raw}" + + +def _color_to_argb(value: str) -> str: + """Convert a benchmark #RRGGBB color to the library's AARRGGBB form.""" + raw = value.lstrip("#").upper() + if len(raw) == 6: + return f"FF{raw}" + if len(raw) == 8: + return raw + raise ValueError(f"Expected a six- or eight-digit hex color, got {value!r}") + + +def _cell_value_from_aspose_cell(cell: Any) -> CellValue: + """Convert an aspose-cells-foss cell to the benchmark's typed value model.""" + formula = getattr(cell, "formula", None) + value = getattr(cell, "value", None) + if isinstance(formula, str) and formula: + formula_text = formula if formula.startswith("=") else f"={formula}" + if formula_text in _ERROR_FORMULA_MAP: + return CellValue( + type=CellType.ERROR, value=_ERROR_FORMULA_MAP[formula_text] + ) + return CellValue(type=CellType.FORMULA, value=value, formula=formula_text) + if value is None: + return CellValue(type=CellType.BLANK) + if isinstance(value, bool): + return CellValue(type=CellType.BOOLEAN, value=value) + if isinstance(value, (int, float)): + return CellValue(type=CellType.NUMBER, value=value) + if isinstance(value, datetime): + if ( + value.hour == 0 + and value.minute == 0 + and value.second == 0 + and value.microsecond == 0 + ): + return CellValue(type=CellType.DATE, value=value.date()) + return CellValue(type=CellType.DATETIME, value=value) + if isinstance(value, date): + return CellValue(type=CellType.DATE, value=value) + if isinstance(value, str): + if value.startswith("#") and value.endswith("!") or value == "#N/A": + return CellValue(type=CellType.ERROR, value=value) + return CellValue(type=CellType.STRING, value=value) + return CellValue(type=CellType.STRING, value=str(value)) + + +def _edge_from_aspose_border(border: Any) -> BorderEdge | None: + """Convert one aspose-cells-foss border side to a benchmark border edge.""" + line_style = getattr(border, "line_style", "none") + if not isinstance(line_style, str) or line_style == "none": + return None + try: + style = BorderStyle(line_style) + except ValueError: + style = BorderStyle.THIN + return BorderEdge( + style=style, color=_color_to_hex(getattr(border, "color", None)) or "#000000" + ) + + +def _set_aspose_border_edge(target: Any, edge: BorderEdge | None) -> None: + """Apply a benchmark border edge to an aspose-cells-foss border side.""" + if edge is None: + target.line_style = "none" + return + target.line_style = edge.style.value + target.color = _color_to_argb(edge.color) + + +def _coordinates(cell_range: str) -> tuple[int, int, int, int]: + """Return zero-based top-left and bottom-right coordinates for an A1 range.""" + normalized = cell_range.replace("$", "").upper() + start, separator, end = normalized.partition(":") + if not separator: + end = start + start_row, start_col = aspose.Cells.coordinate_from_string(start) + end_row, end_col = aspose.Cells.coordinate_from_string(end) + return start_row - 1, start_col - 1, end_row - 1, end_col - 1 + + +def _center_section(value: Any) -> str | None: + """Extract the center section from an OOXML header/footer string.""" + if not isinstance(value, str) or "&C" not in value: + return None + center = value.split("&C", 1)[1] + for marker in ("&L", "&R"): + center = center.split(marker, 1)[0] + return center or None + + +class AsposeCellsFossAdapter(ExcelAdapter): + """Read/write Excel adapter for aspose-cells-foss 26.7.0 and compatible releases.""" + + @property + def info(self) -> LibraryInfo: + return LibraryInfo( + name="aspose-cells-foss", + version=str(getattr(aspose, "__version__", "unknown")), + language="python", + capabilities={"read", "write"}, + ) + + def open_workbook(self, path: Path) -> Any: + """Open an XLSX workbook for reading and modification.""" + return aspose.Workbook(str(path)) + + def close_workbook(self, workbook: Any) -> None: + """Release a workbook; aspose-cells-foss keeps no open file handle.""" + del workbook + + def get_sheet_names(self, workbook: Any) -> list[str]: + """Return worksheet names in workbook order.""" + return [str(worksheet.name) for worksheet in workbook.worksheets] + + def read_sheet_values( + self, workbook: Any, sheet: str, cell_range: str | None = None + ) -> list[list[CellValue]]: + """Read a rectangular cell range as typed benchmark values.""" + worksheet = workbook.get_worksheet(sheet) + if worksheet is None: + raise ValueError(f"Worksheet {sheet!r} not found") + if cell_range is None: + cells = worksheet.cells + if not cells._cells: + return [] + rows_and_columns = [ + aspose.Cells.coordinate_from_string(ref) for ref in cells._cells + ] + min_row = min(row for row, _ in rows_and_columns) + max_row = max(row for row, _ in rows_and_columns) + min_col = min(column for _, column in rows_and_columns) + max_col = max(column for _, column in rows_and_columns) + else: + start_row, start_col, end_row, end_col = _coordinates(cell_range) + min_row, max_row = start_row + 1, end_row + 1 + min_col, max_col = start_col + 1, end_col + 1 + return [ + [_cell_value_from_aspose_cell(cell) for cell in row] + for row in worksheet.cells.iter_rows( + min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col + ) + ] + + def read_cell_value(self, workbook: Any, sheet: str, cell: str) -> CellValue: + """Read a typed value, preserving formula text.""" + return _cell_value_from_aspose_cell(workbook.get_worksheet(sheet).cells[cell]) + + def read_cell_format(self, workbook: Any, sheet: str, cell: str) -> CellFormat: + """Read a cell's font, fill, number-format, and alignment properties.""" + style = workbook.get_worksheet(sheet).cells[cell].style + font = style.font + fill = style.fill + alignment = style.alignment + return CellFormat( + bold=True if font.bold else None, + italic=True if font.italic else None, + underline="single" if font.underline else None, + strikethrough=True if font.strikethrough else None, + font_name=str(font.name) if font.name else None, + font_size=float(font.size) if font.size else None, + font_color=_color_to_hex(font.color), + bg_color=_color_to_hex(fill.foreground_color) + if fill.pattern_type == "solid" + else None, + number_format=str(style.number_format) if style.number_format else None, + h_align=alignment.horizontal if alignment.horizontal != "general" else None, + v_align=alignment.vertical if alignment.vertical != "bottom" else None, + wrap=True if alignment.wrap_text else None, + rotation=alignment.text_rotation if alignment.text_rotation else None, + indent=alignment.indent if alignment.indent else None, + ) + + def read_cell_border(self, workbook: Any, sheet: str, cell: str) -> BorderInfo: + """Read all four and diagonal borders from a cell.""" + borders = workbook.get_worksheet(sheet).cells[cell].style.borders + return BorderInfo( + top=_edge_from_aspose_border(borders.top), + bottom=_edge_from_aspose_border(borders.bottom), + left=_edge_from_aspose_border(borders.left), + right=_edge_from_aspose_border(borders.right), + diagonal_up=_edge_from_aspose_border(borders.diagonal) + if borders.diagonal_up + else None, + diagonal_down=_edge_from_aspose_border(borders.diagonal) + if borders.diagonal_down + else None, + ) + + def read_row_height(self, workbook: Any, sheet: str, row: int) -> float | None: + """Read a 1-indexed row's height in points.""" + value = workbook.get_worksheet(sheet).cells.get_row_height(row - 1) + return float(value) if isinstance(value, (int, float)) else None + + def read_column_width(self, workbook: Any, sheet: str, column: str) -> float | None: + """Read a column's display width in characters.""" + value = workbook.get_worksheet(sheet).cells.get_column_width(column) + return float(value) if isinstance(value, (int, float)) else None + + def read_merged_ranges(self, workbook: Any, sheet: str) -> list[str]: + """Read merged A1 ranges.""" + merged: list[str] = workbook.get_worksheet(sheet).cells.get_merged_cells() + return merged + + def read_conditional_formats(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read conditional-format rules exposed by the FOSS API.""" + rules: list[JSONDict] = [] + for conditional_format in workbook.get_worksheet(sheet).conditional_formats: + rule_type = conditional_format.type + if rule_type == "cellValue": + rule_type = "cellIs" + elif rule_type == "formula": + rule_type = "expression" + rules.append( + { + "range": conditional_format.range, + "rule_type": rule_type, + "operator": conditional_format.operator, + "formula": conditional_format.formula + if conditional_format.formula is not None + else conditional_format.formula1, + "priority": conditional_format.priority, + "stop_if_true": conditional_format.stop_if_true, + "format": { + **( + { + "bg_color": _color_to_hex( + conditional_format.fill.foreground_color + ) + } + if conditional_format.fill.pattern_type == "solid" + and _color_to_hex(conditional_format.fill.foreground_color) + else {} + ), + **( + {"font_color": _color_to_hex(conditional_format.font.color)} + if _color_to_hex(conditional_format.font.color) + not in (None, "#000000") + else {} + ), + }, + } + ) + return rules + + def read_data_validations(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read data-validation rules.""" + validations: list[JSONDict] = [] + for validation in workbook.get_worksheet(sheet).data_validations: + validation_type = _VALIDATION_TYPE_NAMES.get( + validation.type, str(validation.type) + ) + operator = _VALIDATION_OPERATOR_NAMES.get( + validation.operator, str(validation.operator) + ) + validations.append( + { + "range": validation.sqref, + "validation_type": validation_type, + "operator": operator, + "formula1": validation.formula1, + "formula2": validation.formula2, + "allow_blank": validation.allow_blank, + "show_input": validation.show_input_message, + "show_error": validation.show_error_message, + "prompt_title": validation.input_title, + "prompt": validation.input_message, + "error_title": validation.error_title, + "error": validation.error_message, + } + ) + return validations + + def read_hyperlinks(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read worksheet hyperlinks with internal/external targets normalized.""" + worksheet = workbook.get_worksheet(sheet) + return [ + { + "cell": link.range, + "target": link.sub_address if link.sub_address else link.address, + "display": link.text_to_display or worksheet.cells[link.range].value, + "tooltip": link.screen_tip or None, + "internal": bool(link.sub_address), + } + for link in worksheet.hyperlinks + ] + + def read_images(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Reject image reads because one-cell drawing anchors are not surfaced reliably.""" + self.unsupported_operation( + "read_images", + "aspose-cells-foss does not preserve the source one-cell versus two-cell anchor kind.", + ) + + def read_pivot_tables(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Reject pivot reads because the FOSS API has no pivot-table model.""" + self.unsupported_operation( + "read_pivot_tables", "aspose-cells-foss exposes no pivot-table API." + ) + + def read_comments(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read legacy cell comments.""" + worksheet = workbook.get_worksheet(sheet) + return [ + { + "cell": cell_ref, + "text": comment["text"], + "author": comment["author"], + "threaded": False, + } + for cell_ref, cell in worksheet.cells._cells.items() + if (comment := cell.comment) is not None + ] + + def read_freeze_panes(self, workbook: Any, sheet: str) -> JSONDict: + """Read frozen or split pane settings.""" + pane = workbook.get_worksheet(sheet).properties.pane + if pane.state is None: + return {} + result: JSONDict = { + "mode": "freeze" if pane.state in {"frozen", "frozenSplit"} else "split" + } + if pane.x_split is not None: + result["x_split"] = int(pane.x_split) + if pane.y_split is not None: + result["y_split"] = int(pane.y_split) + if pane.top_left_cell is not None: + result["top_left_cell"] = pane.top_left_cell + if pane.active_pane is not None: + result["active_pane"] = pane.active_pane + return result + + def read_named_ranges(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read workbook names plus names local to the requested worksheet.""" + sheet_index = self.get_sheet_names(workbook).index(sheet) + return [ + { + "name": defined_name.name, + "scope": "sheet" + if defined_name.local_sheet_id is not None + else "workbook", + "refers_to": str(defined_name.refers_to).lstrip("="), + } + for defined_name in workbook.properties.defined_names + if defined_name.local_sheet_id is None + or defined_name.local_sheet_id == sheet_index + ] + + def read_tables(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read structured table definitions.""" + return [ + { + "name": table.display_name or table.name, + "ref": table.ref, + "header_row": table.has_headers, + "totals_row": table.show_totals_row, + "style": table.table_style_info.name + if table.table_style_info + else None, + "columns": [column.name for column in table.columns], + "autofilter": table.show_auto_filter, + } + for table in workbook.get_worksheet(sheet).tables + ] + + def read_sheet_protection(self, workbook: Any, sheet: str) -> JSONDict: + """Read raw OOXML-equivalent sheet-protection flags.""" + protection = workbook.get_worksheet(sheet).properties.protection + return { + "protected": bool(protection.sheet), + "password_hash_present": bool( + protection.password + or protection.hash_value + or protection.algorithm_name + ), + "format_cells": protection.format_cells, + "insert_rows": protection.insert_rows, + "select_locked_cells": protection.select_locked_cells, + "select_unlocked_cells": protection.select_unlocked_cells, + "sort": protection.sort, + "auto_filter": protection.auto_filter, + } + + def read_page_setup(self, workbook: Any, sheet: str) -> JSONDict: + """Read print settings supported by the FOSS worksheet-properties API.""" + worksheet = workbook.get_worksheet(sheet) + page_setup = worksheet.properties.page_setup + header_footer = worksheet.properties.header_footer + return { + "orientation": page_setup.orientation, + "fit_to_width": page_setup.fit_to_width, + "fit_to_height": page_setup.fit_to_height, + "scale": page_setup.scale, + "print_title_rows": None, + "header_center": _center_section(header_footer.odd_header), + "footer_center": _center_section(header_footer.odd_footer), + } + + def read_chart_anchors(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read charts and their explicit two-cell drawing anchors.""" + results: list[JSONDict] = [] + for chart in workbook.get_worksheet(sheet).charts: + chart_type = getattr(chart.type, "name", str(chart.type)).lower() + results.append( + { + "type": chart_type, + "anchor_type": "twoCell", + "from": aspose.Cells.coordinate_to_string( + chart._upper_left_row + 1, chart._upper_left_column + 1 + ), + "to": aspose.Cells.coordinate_to_string( + chart._lower_right_row + 1, chart._lower_right_column + 1 + ), + } + ) + return results + + def create_workbook(self) -> Any: + """Create an empty workbook without an implicit worksheet.""" + workbook = aspose.Workbook() + workbook.remove_worksheet(0) + return workbook + + def add_sheet(self, workbook: Any, name: str) -> None: + """Add a named worksheet.""" + workbook.add_worksheet(name) + + def write_sheet_values( + self, workbook: Any, sheet: str, start_cell: str, values: list[list[Any]] + ) -> None: + """Write a rectangular grid of raw values for throughput workloads.""" + start_row, start_col = aspose.Cells.coordinate_from_string(start_cell) + cells = workbook.get_worksheet(sheet).cells + for row_offset, values_row in enumerate(values): + for column_offset, raw_value in enumerate(values_row): + if raw_value is not None: + cells.cell( + start_row + row_offset, start_col + column_offset + ).value = raw_value + + def write_cell_value( + self, workbook: Any, sheet: str, cell: str, value: CellValue + ) -> None: + """Write a typed cell value, including formulas and formula-produced errors.""" + target = workbook.get_worksheet(sheet).cells[cell] + target.formula = None + if value.type == CellType.BLANK: + target.value = None + elif value.type == CellType.FORMULA: + formula = value.formula if value.formula is not None else value.value + if not isinstance(formula, str): + raise ValueError("Formula CellValue must provide a formula string") + target.formula = formula if formula.startswith("=") else f"={formula}" + target.value = None + elif value.type == CellType.ERROR: + formula = _ERROR_VALUE_FORMULA_MAP.get(str(value.value)) + if formula is None: + self.unsupported_operation( + "write_cell_value", + f"Cannot serialize Excel error {value.value!r} without a formula.", + ) + target.formula = formula + target.value = None + else: + target.value = value.value + + def write_cell_format( + self, workbook: Any, sheet: str, cell: str, format: CellFormat + ) -> None: + """Apply benchmark formatting fields the FOSS style model can represent.""" + style = workbook.get_worksheet(sheet).cells[cell].style + if format.bold is not None: + style.font.bold = format.bold + if format.italic is not None: + style.font.italic = format.italic + if format.underline is not None: + if format.underline not in {"single", True}: + self.unsupported_operation( + "write_cell_format", + ( + "aspose-cells-foss supports only a single underline, " + "not accounting or double variants." + ), + ) + style.font.underline = True + if format.strikethrough is not None: + style.font.strikethrough = format.strikethrough + if format.font_name is not None: + style.font.name = format.font_name + if format.font_size is not None: + style.font.size = format.font_size + if format.font_color is not None: + style.font.color = _color_to_argb(format.font_color) + if format.bg_color is not None: + style.fill.set_solid_fill(_color_to_argb(format.bg_color)) + if format.number_format is not None: + style.number_format = format.number_format + if format.h_align is not None: + style.alignment.horizontal = format.h_align + if format.v_align is not None: + style.alignment.vertical = format.v_align + if format.wrap is not None: + style.alignment.wrap_text = format.wrap + if format.rotation is not None: + style.alignment.text_rotation = format.rotation + if format.indent is not None: + style.alignment.indent = format.indent + + def write_cell_border( + self, workbook: Any, sheet: str, cell: str, border: BorderInfo + ) -> None: + """Apply four-side and diagonal borders.""" + borders = workbook.get_worksheet(sheet).cells[cell].style.borders + _set_aspose_border_edge(borders.top, border.top) + _set_aspose_border_edge(borders.bottom, border.bottom) + _set_aspose_border_edge(borders.left, border.left) + _set_aspose_border_edge(borders.right, border.right) + diagonal = border.diagonal_up or border.diagonal_down + _set_aspose_border_edge(borders.diagonal, diagonal) + borders.diagonal_up = border.diagonal_up is not None + borders.diagonal_down = border.diagonal_down is not None + + def set_row_height( + self, workbook: Any, sheet: str, row: int, height: float + ) -> None: + """Set a 1-indexed row height in points.""" + workbook.get_worksheet(sheet).cells.set_row_height(row - 1, height) + + def set_column_width( + self, workbook: Any, sheet: str, column: str, width: float + ) -> None: + """Set a column width in display characters.""" + workbook.get_worksheet(sheet).cells.set_column_width(column, width) + + def merge_cells(self, workbook: Any, sheet: str, cell_range: str) -> None: + """Merge an A1 range.""" + workbook.get_worksheet(sheet).cells.merge_range(cell_range) + + def add_conditional_format(self, workbook: Any, sheet: str, rule: JSONDict) -> None: + """Add a conditional-format rule.""" + config = rule.get("cf_rule", rule) + rule_type = str(config.get("rule_type") or "") + type_mapping = { + "cellIs": "cellValue", + "cellIsRule": "cellValue", + "expression": "formula", + } + aspose_type = type_mapping.get(rule_type, rule_type) + if not aspose_type: + raise ValueError("Conditional-format rule requires rule_type") + conditional_format = workbook.get_worksheet(sheet).conditional_formats.add() + conditional_format.type = aspose_type + conditional_format.range = config.get("range") + if config.get("operator") is not None: + conditional_format.operator = config["operator"] + formula = config.get("formula") + if aspose_type == "formula": + conditional_format.formula = formula + elif formula is not None: + conditional_format.formula1 = formula + if config.get("priority") is not None: + conditional_format.priority = int(config["priority"]) + if config.get("stop_if_true") is not None: + conditional_format.stop_if_true = bool(config["stop_if_true"]) + style = config.get("format") or {} + if style.get("bg_color"): + conditional_format.fill.set_solid_fill( + _color_to_argb(str(style["bg_color"])) + ) + if style.get("font_color"): + conditional_format.font.color = _color_to_argb(str(style["font_color"])) + + def add_data_validation( + self, workbook: Any, sheet: str, validation: JSONDict + ) -> None: + """Add an Excel data-validation rule.""" + config = validation.get("validation", validation) + raw_type = str(config.get("validation_type") or "none") + validation_type = _VALIDATION_TYPES.get(raw_type) + if validation_type is None: + self.unsupported_operation( + "add_data_validation", f"Unsupported data-validation type {raw_type!r}." + ) + raw_operator = str(config.get("operator") or "between") + operator = _VALIDATION_OPERATORS.get(raw_operator) + if operator is None: + self.unsupported_operation( + "add_data_validation", + f"Unsupported data-validation operator {raw_operator!r}.", + ) + target = workbook.get_worksheet(sheet).data_validations.add( + str(config.get("range") or ""), + validation_type, + operator, + config.get("formula1"), + config.get("formula2"), + ) + if config.get("allow_blank") is not None: + target.allow_blank = bool(config["allow_blank"]) + if config.get("show_input") is not None: + target.show_input_message = bool(config["show_input"]) + if config.get("show_error") is not None: + target.show_error_message = bool(config["show_error"]) + if config.get("prompt_title") is not None: + target.input_title = str(config["prompt_title"]) + if config.get("prompt") is not None: + target.input_message = str(config["prompt"]) + if config.get("error_title") is not None: + target.error_title = str(config["error_title"]) + if config.get("error") is not None: + target.error_message = str(config["error"]) + + def add_hyperlink(self, workbook: Any, sheet: str, link: JSONDict) -> None: + """Add an internal or external hyperlink.""" + config = link.get("hyperlink", link) + cell = str(config.get("cell") or "") + target = str(config.get("target") or "") + internal = bool(config.get("internal")) + if not cell or not target: + raise ValueError("Hyperlinks require both cell and target") + hyperlink = workbook.get_worksheet(sheet).hyperlinks.add( + cell, + "" if internal else target, + target.lstrip("#") if internal else "", + str(config.get("display") or ""), + str(config.get("tooltip") or ""), + ) + if config.get("display") is not None: + workbook.get_worksheet(sheet).cells[cell].value = config["display"] + del hyperlink + + def add_image(self, workbook: Any, sheet: str, image: JSONDict) -> None: + """Reject image writes because the adapter cannot create one-cell anchors.""" + self.unsupported_operation( + "add_image", + ( + "aspose-cells-foss writes only two-cell picture anchors, " + "while the benchmark requires one-cell anchors." + ), + ) + + def add_pivot_table(self, workbook: Any, sheet: str, pivot: JSONDict) -> None: + """Reject pivot writes because the FOSS API has no pivot-table model.""" + self.unsupported_operation( + "add_pivot_table", "aspose-cells-foss exposes no pivot-table API." + ) + + def add_comment(self, workbook: Any, sheet: str, comment: JSONDict) -> None: + """Add a legacy note/comment to a cell.""" + config = comment.get("comment", comment) + cell = config.get("cell") + text = config.get("text") + if cell is None or text is None: + raise ValueError("Comments require both cell and text") + workbook.get_worksheet(sheet).cells[str(cell)].set_comment( + str(text), str(config.get("author") or "") + ) + + def set_freeze_panes(self, workbook: Any, sheet: str, settings: JSONDict) -> None: + """Set frozen or split worksheet panes.""" + config = settings.get("freeze", settings) + mode = config.get("mode") + if mode not in {"freeze", "split"}: + self.unsupported_operation( + "set_freeze_panes", + f"Unsupported pane mode {mode!r}; expected 'freeze' or 'split'.", + ) + pane = workbook.get_worksheet(sheet).properties.pane + pane.state = "frozen" if mode == "freeze" else "split" + pane.x_split = config.get("x_split") + pane.y_split = config.get("y_split") + pane.top_left_cell = config.get("top_left_cell") + pane.active_pane = config.get("active_pane") + + def add_named_range(self, workbook: Any, sheet: str, named_range: JSONDict) -> None: + """Add a workbook- or sheet-scoped named range.""" + config = named_range.get("named_range", named_range) + name = config.get("name") + refers_to = config.get("refers_to") + if not name or not refers_to: + raise ValueError("Named ranges require name and refers_to") + scope = config.get("scope") or "workbook" + local_sheet_id = ( + self.get_sheet_names(workbook).index(sheet) if scope == "sheet" else None + ) + workbook.properties.defined_names.add( + DefinedName(str(name), str(refers_to).lstrip("="), local_sheet_id) + ) + + def add_table(self, workbook: Any, sheet: str, table: JSONDict) -> None: + """Add a structured table and apply its supported metadata.""" + config = table.get("table", table) + name = config.get("name") + cell_range = config.get("ref") or config.get("range") + if not name or not cell_range: + raise ValueError("Tables require both name and ref") + worksheet = workbook.get_worksheet(sheet) + created = worksheet.tables.add_with_range( + str(cell_range), str(name), bool(config.get("header_row", True)) + ) + created.show_totals_row = bool(config.get("totals_row", False)) + created.show_auto_filter = bool(config.get("autofilter", True)) + if config.get("style") is not None: + created.table_style_info.name = str(config["style"]) + columns = config.get("columns") + if isinstance(columns, list) and len(columns) == len(created.columns): + for column, name_value in zip(created.columns, columns, strict=True): + column.name = str(name_value) + + def set_sheet_protection( + self, workbook: Any, sheet: str, settings: JSONDict + ) -> None: + """Apply raw OOXML-equivalent sheet protection settings.""" + config = settings.get("protection", settings) + protection = workbook.get_worksheet(sheet).properties.protection + property_names = { + "protected": "sheet", + "format_cells": "format_cells", + "insert_rows": "insert_rows", + "select_locked_cells": "select_locked_cells", + "select_unlocked_cells": "select_unlocked_cells", + "sort": "sort", + "auto_filter": "auto_filter", + } + for input_name, property_name in property_names.items(): + if config.get(input_name) is not None: + setattr(protection, property_name, bool(config[input_name])) + if config.get("password") is not None: + protection.password = str(config["password"]) + + def set_page_setup(self, workbook: Any, sheet: str, settings: JSONDict) -> None: + """Apply supported page setup and centered header/footer text.""" + config = settings.get("page_setup", settings) + if config.get("print_title_rows") is not None: + self.unsupported_operation( + "set_page_setup", "aspose-cells-foss has no print-title-rows API." + ) + worksheet = workbook.get_worksheet(sheet) + page_setup = worksheet.properties.page_setup + for key in ("orientation", "fit_to_width", "fit_to_height", "scale"): + if config.get(key) is not None: + setattr(page_setup, key, config[key]) + if config.get("header_center") is not None: + worksheet.properties.header_footer.odd_header = ( + f"&C{config['header_center']}" + ) + if config.get("footer_center") is not None: + worksheet.properties.header_footer.odd_footer = ( + f"&C{config['footer_center']}" + ) + + def add_chart_with_anchor(self, workbook: Any, sheet: str, chart: JSONDict) -> None: + """Add a line or bar chart with a two-cell anchor and first data series.""" + config = chart.get("chart", chart) + chart_type_name = str(config.get("type") or "bar").upper() + chart_type = getattr(aspose.ChartType, chart_type_name, None) + if chart_type not in {aspose.ChartType.BAR, aspose.ChartType.LINE}: + self.unsupported_operation( + "add_chart_with_anchor", + f"Unsupported chart type {config.get('type')!r}.", + ) + data_ref = config.get("data_ref") + if not data_ref: + raise ValueError("add_chart_with_anchor requires data_ref") + from_row, from_column, to_row, to_column = _coordinates( + f"{config.get('from') or 'B2'}:{config.get('to') or 'H12'}" + ) + charts = workbook.get_worksheet(sheet).charts + chart_index = charts.add(chart_type, from_row, from_column, to_row, to_column) + series_chart = charts[chart_index] + series_chart.add_series(str(data_ref), config.get("categories_ref")) + + def save_workbook(self, workbook: Any, path: Path) -> None: + """Save a workbook as XLSX.""" + workbook.save(str(path)) diff --git a/src/excelbench/harness/adapters/base.py b/src/excelbench/harness/adapters/base.py index 1e2d0fa..182308d 100644 --- a/src/excelbench/harness/adapters/base.py +++ b/src/excelbench/harness/adapters/base.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod from pathlib import Path -from typing import Any +from typing import Any, NoReturn from excelbench.models import ( BorderInfo, @@ -18,6 +18,7 @@ JSONDict = dict[str, Any] + class UnsupportedAdapterOperationError(NotImplementedError): """Structured exception for adapter operations a library cannot support.""" @@ -31,7 +32,9 @@ def __init__(self, *, adapter: str, operation: str, reason: str) -> None: def _infer_diagnostic_category(exc: Exception) -> DiagnosticCategory: name = type(exc).__name__.lower() message = str(exc).lower() - if isinstance(exc, (FileNotFoundError, PermissionError, IsADirectoryError, OSError)): + if isinstance( + exc, (FileNotFoundError, PermissionError, IsADirectoryError, OSError) + ): if "format" in message or "zip" in message or "corrupt" in message: return DiagnosticCategory.PARSE return DiagnosticCategory.FILE_IO @@ -92,13 +95,15 @@ def supports_read_path(self, path: Path) -> bool: suffix = path.suffix.lower() return suffix in self.supported_read_extensions - def unsupported_operation(self, operation: str, reason: str) -> None: - """Raise a structured unsupported-feature exception for adapter methods.""" + def unsupported_operation(self, operation: str, reason: str) -> NoReturn: + """Raise a structured unsupported-feature exception for adapter methods. + + Never returns: the raised error is the structured unsupported signal. + """ raise UnsupportedAdapterOperationError( adapter=self.name, operation=operation, reason=reason ) - def map_error_to_diagnostic( self, *, @@ -387,6 +392,81 @@ def add_table(self, workbook: Any, sheet: str, table: JSONDict) -> None: raise NotImplementedError(f"{self.name} does not implement table writes") + def read_sheet_protection(self, workbook: Any, sheet: str) -> JSONDict: + """Read sheet protection settings (raw OOXML attribute semantics). + + Returns a dict with keys (attribute True means the action is + BLOCKED while protection is active, matching sheetProtection XML): + - protected: bool (sheetProtection@sheet) + - password_hash_present: bool (any password hash stored) + - format_cells: bool | None + - insert_rows: bool | None + - select_locked_cells: bool | None + - select_unlocked_cells: bool | None + - sort: bool | None + - auto_filter: bool | None + """ + + raise NotImplementedError( + f"{self.name} does not implement sheet protection reads" + ) + + def set_sheet_protection( + self, workbook: Any, sheet: str, settings: JSONDict + ) -> None: + """Apply sheet protection settings. + + settings uses the same keys as read_sheet_protection (without + password_hash_present; use settings["password"] for a plain password + when the library hashes it internally). + """ + + raise NotImplementedError( + f"{self.name} does not implement sheet protection writes" + ) + + def read_page_setup(self, workbook: Any, sheet: str) -> JSONDict: + """Read page setup / print settings. + + Returns a dict with keys: + - orientation: "portrait" | "landscape" | None + - fit_to_width: int | None + - fit_to_height: int | None + - scale: int | None + - print_title_rows: str | None (e.g. "$1:$2") + - header_center: str | None + - footer_center: str | None + """ + + raise NotImplementedError(f"{self.name} does not implement page setup reads") + + def set_page_setup(self, workbook: Any, sheet: str, settings: JSONDict) -> None: + """Apply page setup / print settings (same keys as read_page_setup).""" + + raise NotImplementedError(f"{self.name} does not implement page setup writes") + + def read_chart_anchors(self, workbook: Any, sheet: str) -> list[JSONDict]: + """Read chart anchors from a sheet. + + Returns a list of dicts with keys: + - type: normalized chart type ("bar", "line", "pie", ...) + - anchor_type: "twoCell" | "oneCell" | "absolute" | None + - from: top-left cell ref (e.g. "B2") + - to: bottom-right cell ref (e.g. "H12"), None when not two-cell + """ + + raise NotImplementedError(f"{self.name} does not implement chart anchor reads") + + def add_chart_with_anchor(self, workbook: Any, sheet: str, chart: JSONDict) -> None: + """Add a chart with an explicit two-cell anchor. + + chart dict keys: type ("bar" | "line"), from, to (cell refs), + data_ref (range on the same sheet feeding the first series), + categories_ref (optional range for category labels). + """ + + raise NotImplementedError(f"{self.name} does not implement chart anchor writes") + # ========================================================================= # Write Operations # ========================================================================= @@ -501,7 +581,9 @@ def add_conditional_format(self, workbook: Any, sheet: str, rule: JSONDict) -> N ... @abstractmethod - def add_data_validation(self, workbook: Any, sheet: str, validation: JSONDict) -> None: + def add_data_validation( + self, workbook: Any, sheet: str, validation: JSONDict + ) -> None: """Add a data validation rule to a sheet.""" ... @@ -608,7 +690,9 @@ def merge_cells(self, workbook: Any, sheet: str, cell_range: str) -> None: def add_conditional_format(self, workbook: Any, sheet: str, rule: JSONDict) -> None: raise NotImplementedError(f"{self.name} is read-only") - def add_data_validation(self, workbook: Any, sheet: str, validation: JSONDict) -> None: + def add_data_validation( + self, workbook: Any, sheet: str, validation: JSONDict + ) -> None: raise NotImplementedError(f"{self.name} is read-only") def add_hyperlink(self, workbook: Any, sheet: str, link: JSONDict) -> None: diff --git a/src/excelbench/harness/adapters/openpyxl_adapter.py b/src/excelbench/harness/adapters/openpyxl_adapter.py index a22e256..e5870f7 100644 --- a/src/excelbench/harness/adapters/openpyxl_adapter.py +++ b/src/excelbench/harness/adapters/openpyxl_adapter.py @@ -107,7 +107,12 @@ def _cell_value_from_openpyxl_cell(c: Any) -> CellValue: return CellValue(type=CellType.DATE, value=value) if isinstance(value, datetime): - if value.hour == 0 and value.minute == 0 and value.second == 0 and value.microsecond == 0: + if ( + value.hour == 0 + and value.minute == 0 + and value.second == 0 + and value.microsecond == 0 + ): return CellValue(type=CellType.DATE, value=value.date()) return CellValue(type=CellType.DATETIME, value=value) @@ -127,7 +132,9 @@ def _cell_value_from_openpyxl_cell(c: Any) -> CellValue: if not formula_str.startswith("=") and value: formula_str = str(value) if formula_str in ERROR_FORMULA_MAP: - return CellValue(type=CellType.ERROR, value=ERROR_FORMULA_MAP[formula_str]) + return CellValue( + type=CellType.ERROR, value=ERROR_FORMULA_MAP[formula_str] + ) return CellValue(type=CellType.FORMULA, value=value, formula=formula_str) return CellValue(type=CellType.STRING, value=value) @@ -395,7 +402,9 @@ def read_merged_ranges(self, workbook: Workbook, sheet: str) -> list[str]: ws = workbook[sheet] return [str(rng) for rng in ws.merged_cells.ranges] - def read_conditional_formats(self, workbook: Workbook, sheet: str) -> list[JSONDict]: + def read_conditional_formats( + self, workbook: Workbook, sheet: str + ) -> list[JSONDict]: ws = workbook[sheet] rules: list[JSONDict] = [] cf_rules = getattr(ws.conditional_formatting, "_cf_rules", {}) @@ -407,7 +416,9 @@ def read_conditional_formats(self, workbook: Workbook, sheet: str) -> list[JSOND range_value = str(sqref) if range_value.startswith("", "").strip() + range_value.replace("", "") + .strip() ) for rule in rule_list: entry: dict[str, Any] = { @@ -422,11 +433,19 @@ def read_conditional_formats(self, workbook: Workbook, sheet: str) -> list[JSOND if getattr(rule, "formula", None): entry["formula"] = rule.formula[0] if rule.formula else None dxf = getattr(rule, "dxf", None) - if dxf and getattr(dxf, "fill", None) and getattr(dxf.fill, "fgColor", None): + if ( + dxf + and getattr(dxf, "fill", None) + and getattr(dxf.fill, "fgColor", None) + ): bg = _openpyxl_color_to_hex(dxf.fill.fgColor) if bg: entry["format"]["bg_color"] = bg - if dxf and getattr(dxf, "font", None) and getattr(dxf.font, "color", None): + if ( + dxf + and getattr(dxf, "font", None) + and getattr(dxf.font, "color", None) + ): fc = _openpyxl_color_to_hex(dxf.font.color) if fc: entry["format"]["font_color"] = fc @@ -534,11 +553,15 @@ def read_pivot_tables(self, workbook: Workbook, sheet: str) -> list[JSONDict]: for pivot in pivot_list: source_range = None cache = getattr(pivot, "cache", None) - cache_source = getattr(cache, "cacheSource", None) if cache is not None else None + cache_source = ( + getattr(cache, "cacheSource", None) if cache is not None else None + ) if cache_source is not None: worksheet_source = getattr(cache_source, "worksheetSource", None) ref = ( - getattr(worksheet_source, "ref", None) if worksheet_source is not None else None + getattr(worksheet_source, "ref", None) + if worksheet_source is not None + else None ) source_sheet = ( getattr(worksheet_source, "sheet", None) @@ -635,7 +658,11 @@ def _normalize_refers_to(value: Any) -> str: sheet_part, addr = raw.split("!", 1) # Strip only wrapper quotes used for sheet names with spaces. # Preserve embedded apostrophes by unescaping doubled quotes. - if sheet_part.startswith("'") and sheet_part.endswith("'") and len(sheet_part) >= 2: + if ( + sheet_part.startswith("'") + and sheet_part.endswith("'") + and len(sheet_part) >= 2 + ): sheet_part = sheet_part[1:-1].replace("''", "'") return f"{sheet_part}!{addr}" @@ -712,7 +739,11 @@ def read_tables(self, workbook: Workbook, sheet: str) -> list[JSONDict]: ref = getattr(tbl, "ref", None) if isinstance(ref, str) and ref: min_col, min_row, max_col, _ = range_boundaries(ref) - if min_col is not None and min_row is not None and max_col is not None: + if ( + min_col is not None + and min_row is not None + and max_col is not None + ): for c in range(int(min_col), int(max_col) + 1): v = ws.cell(row=int(min_row), column=c).value cols.append("" if v is None else str(v)) @@ -723,7 +754,8 @@ def read_tables(self, workbook: Workbook, sheet: str) -> list[JSONDict]: out.append( { - "name": getattr(tbl, "displayName", None) or getattr(tbl, "name", None), + "name": getattr(tbl, "displayName", None) + or getattr(tbl, "name", None), "ref": getattr(tbl, "ref", None), "header_row": getattr(tbl, "headerRowCount", 1) != 0, "totals_row": (getattr(tbl, "totalsRowCount", 0) or 0) > 0, @@ -968,7 +1000,9 @@ def merge_cells(self, workbook: Workbook, sheet: str, cell_range: str) -> None: ws = workbook[sheet] ws.merge_cells(cell_range) - def add_conditional_format(self, workbook: Workbook, sheet: str, rule: JSONDict) -> None: + def add_conditional_format( + self, workbook: Workbook, sheet: str, rule: JSONDict + ) -> None: ws = workbook[sheet] cf = rule.get("cf_rule", rule) range_ref = cf.get("range") @@ -983,7 +1017,9 @@ def add_conditional_format(self, workbook: Workbook, sheet: str, rule: JSONDict) if fmt.get("bg_color"): hex_color = fmt["bg_color"].lstrip("#") fill = PatternFill( - start_color=f"FF{hex_color}", end_color=f"FF{hex_color}", fill_type="solid" + start_color=f"FF{hex_color}", + end_color=f"FF{hex_color}", + fill_type="solid", ) if fmt.get("font_color"): hex_color = fmt["font_color"].lstrip("#") @@ -1028,7 +1064,9 @@ def add_conditional_format(self, workbook: Workbook, sheet: str, rule: JSONDict) rule_obj.priority = priority ws.conditional_formatting.add(range_ref, rule_obj) - def add_data_validation(self, workbook: Workbook, sheet: str, validation: JSONDict) -> None: + def add_data_validation( + self, workbook: Workbook, sheet: str, validation: JSONDict + ) -> None: ws = workbook[sheet] v = validation.get("validation", validation) dv = DataValidation( @@ -1105,7 +1143,9 @@ def add_comment(self, workbook: Workbook, sheet: str, comment: JSONDict) -> None c = c_obj c.comment = Comment(text, author) - def add_named_range(self, workbook: Workbook, sheet: str, named_range: JSONDict) -> None: + def add_named_range( + self, workbook: Workbook, sheet: str, named_range: JSONDict + ) -> None: from openpyxl.workbook.defined_name import DefinedName data = named_range.get("named_range", named_range) @@ -1119,7 +1159,11 @@ def add_named_range(self, workbook: Workbook, sheet: str, named_range: JSONDict) refers_to_str = str(refers_to) dn = DefinedName( str(name), - attr_text=(f"={refers_to_str}" if not refers_to_str.startswith("=") else refers_to_str), + attr_text=( + f"={refers_to_str}" + if not refers_to_str.startswith("=") + else refers_to_str + ), ) if scope == "sheet": ws = workbook[sheet] @@ -1174,7 +1218,8 @@ def add_table(self, workbook: Workbook, sheet: str, table: JSONDict) -> None: inferred.append("" if v is None else str(v)) if inferred: tbl.tableColumns = [ - TableColumn(id=i + 1, name=str(col)) for i, col in enumerate(inferred) + TableColumn(id=i + 1, name=str(col)) + for i, col in enumerate(inferred) ] except Exception: # Best-effort: if we can't infer column names from header cells, @@ -1187,7 +1232,9 @@ def add_table(self, workbook: Workbook, sheet: str, table: JSONDict) -> None: ws = workbook[sheet] ws.add_table(tbl) - def set_freeze_panes(self, workbook: Workbook, sheet: str, settings: JSONDict) -> None: + def set_freeze_panes( + self, workbook: Workbook, sheet: str, settings: JSONDict + ) -> None: ws = workbook[sheet] cfg = settings.get("freeze", settings) mode = cfg.get("mode") @@ -1210,3 +1257,151 @@ def set_freeze_panes(self, workbook: Workbook, sheet: str, settings: JSONDict) - if cfg.get("active_pane") is not None: pane.activePane = cfg["active_pane"] pane.state = "split" + + def read_sheet_protection(self, workbook: Workbook, sheet: str) -> JSONDict: + prot = workbook[sheet].protection + return { + "protected": bool(prot.sheet), + "password_hash_present": bool(prot.password), + "format_cells": prot.formatCells, + "insert_rows": prot.insertRows, + "select_locked_cells": prot.selectLockedCells, + "select_unlocked_cells": prot.selectUnlockedCells, + "sort": prot.sort, + "auto_filter": prot.autoFilter, + } + + def set_sheet_protection( + self, workbook: Workbook, sheet: str, settings: JSONDict + ) -> None: + cfg = settings.get("protection", settings) + prot = workbook[sheet].protection + if cfg.get("protected") is not None: + prot.sheet = bool(cfg.get("protected")) + if cfg.get("format_cells") is not None: + prot.formatCells = bool(cfg["format_cells"]) + if cfg.get("insert_rows") is not None: + prot.insertRows = bool(cfg["insert_rows"]) + if cfg.get("select_locked_cells") is not None: + prot.selectLockedCells = bool(cfg["select_locked_cells"]) + if cfg.get("select_unlocked_cells") is not None: + prot.selectUnlockedCells = bool(cfg["select_unlocked_cells"]) + if cfg.get("sort") is not None: + prot.sort = bool(cfg["sort"]) + if cfg.get("auto_filter") is not None: + prot.autoFilter = bool(cfg["auto_filter"]) + password = cfg.get("password") + if password: + prot.set_password(str(password)) + + def read_page_setup(self, workbook: Workbook, sheet: str) -> JSONDict: + ws = workbook[sheet] + ps = ws.page_setup + return { + "orientation": ps.orientation, + "fit_to_width": ps.fitToWidth, + "fit_to_height": ps.fitToHeight, + "scale": ps.scale, + "print_title_rows": ws.print_title_rows, + "header_center": ws.oddHeader.center.text if ws.oddHeader.center else None, + "footer_center": ws.oddFooter.center.text if ws.oddFooter.center else None, + } + + def set_page_setup( + self, workbook: Workbook, sheet: str, settings: JSONDict + ) -> None: + cfg = settings.get("page_setup", settings) + ws = workbook[sheet] + ps = ws.page_setup + if cfg.get("orientation") is not None: + ps.orientation = str(cfg["orientation"]) + if cfg.get("fit_to_width") is not None: + ps.fitToWidth = int(cfg["fit_to_width"]) + if cfg.get("fit_to_height") is not None: + ps.fitToHeight = int(cfg["fit_to_height"]) + if cfg.get("scale") is not None: + ps.scale = int(cfg["scale"]) + if cfg.get("print_title_rows") is not None: + ws.print_title_rows = str(cfg["print_title_rows"]) + if cfg.get("header_center") is not None: + ws.oddHeader.center.text = str(cfg["header_center"]) + if cfg.get("footer_center") is not None: + ws.oddFooter.center.text = str(cfg["footer_center"]) + + def read_chart_anchors(self, workbook: Workbook, sheet: str) -> list[JSONDict]: + from openpyxl.chart._chart import ChartBase + from openpyxl.drawing.spreadsheet_drawing import TwoCellAnchor + from openpyxl.utils.cell import get_column_letter + + def _cell(marker: Any) -> str | None: + if marker is None: + return None + return f"{get_column_letter(marker.col + 1)}{marker.row + 1}" + + results: list[JSONDict] = [] + for chart in workbook[sheet]._charts: + if not isinstance(chart, ChartBase): + continue + anchor = getattr(chart, "anchor", None) + anchor_type = type(anchor).__name__ if anchor is not None else None + from_ref = ( + _cell(getattr(anchor, "_from", None)) if anchor is not None else None + ) + to_ref = ( + _cell(getattr(anchor, "to", None)) + if isinstance(anchor, TwoCellAnchor) + else None + ) + normalized_type = type(chart).__name__.replace("Chart", "").lower() or None + if isinstance(normalized_type, str): + normalized_type = normalized_type or None + results.append( + { + "type": normalized_type, + "anchor_type": "twoCell" + if isinstance(anchor, TwoCellAnchor) + else ("oneCell" if anchor_type == "OneCellAnchor" else None), + "from": from_ref, + "to": to_ref, + } + ) + return results + + def add_chart_with_anchor( + self, workbook: Workbook, sheet: str, chart: JSONDict + ) -> None: + from openpyxl.chart import BarChart, LineChart, Reference + from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor + from openpyxl.utils.cell import coordinate_to_tuple + + cfg = chart.get("chart", chart) + chart_type = str(cfg.get("type") or "bar").lower() + data_ref = str(cfg.get("data_ref") or "") + if not data_ref: + raise ValueError("add_chart_with_anchor requires data_ref") + + ws = workbook[sheet] + values = Reference( + ws, range_string=data_ref if "!" in data_ref else f"{ws.title}!{data_ref}" + ) + series_chart: Any + if chart_type == "line": + series_chart = LineChart() + else: + series_chart = BarChart() + series_chart.add_data(values, titles_from_data=False) + cats = cfg.get("categories_ref") + if cats: + cat_ref = Reference( + ws, range_string=cats if "!" in cats else f"{ws.title}!{cats}" + ) + series_chart.set_categories(cat_ref) + + from_row, from_col = coordinate_to_tuple(str(cfg.get("from") or "B2")) + to_row, to_col = coordinate_to_tuple(str(cfg.get("to") or "H12")) + anchor = TwoCellAnchor( + _from=AnchorMarker(col=from_col - 1, colOff=0, row=from_row - 1, rowOff=0), + to=AnchorMarker(col=to_col - 1, colOff=0, row=to_row - 1, rowOff=0), + ) + series_chart.anchor = anchor + ws.add_chart(series_chart) diff --git a/src/excelbench/harness/adapters/wolfxl_adapter.py b/src/excelbench/harness/adapters/wolfxl_adapter.py index d57557f..c7b9b73 100644 --- a/src/excelbench/harness/adapters/wolfxl_adapter.py +++ b/src/excelbench/harness/adapters/wolfxl_adapter.py @@ -1,28 +1,19 @@ -"""wolfxl — hybrid Rust adapter: calamine (read) + rust_xlsxwriter (write). - -Combines the fastest Rust Excel reader (calamine with style support) and the -fastest Rust writer (rust_xlsxwriter) into a single full-fidelity R+W adapter. -""" +"""Adapter for WolfXL's public openpyxl-compatible Python API.""" import posixpath import zipfile +from datetime import date, datetime from pathlib import Path from typing import Any from xml.etree import ElementTree as ET +import wolfxl + from excelbench.harness.adapters.base import ExcelAdapter -from excelbench.harness.adapters.rust_adapter_utils import ( - border_to_dict, - cell_value_from_payload, - dict_to_border, - dict_to_format, - format_to_dict, - get_rust_backend_version, - payload_from_cell_value, - rust_xlsxwriter_row_index, -) from excelbench.models import ( + BorderEdge, BorderInfo, + BorderStyle, CellFormat, CellType, CellValue, @@ -31,37 +22,80 @@ JSONDict = dict[str, Any] -try: - import wolfxl._rust as _excelbench_rust -except ImportError as e: # pragma: no cover - raise ImportError("wolfxl._rust unavailable — wolfxl adapter requires it") from e +# Formulas that produce known error values. WolfXL writes formulas rather than +# cached error values, so preserve the benchmark's normal error-write contract. +ERROR_FORMULA_MAP = { + "=1/0": "#DIV/0!", + "=NA()": "#N/A", + '="text"+1': "#VALUE!", +} -if getattr(_excelbench_rust, "CalamineStyledBook", None) is None: # pragma: no cover - raise ImportError("wolfxl._rust built without calamine backend") -if ( - getattr(_excelbench_rust, "NativeWorkbook", None) is None - and getattr(_excelbench_rust, "RustXlsxWriterBook", None) is None -): # pragma: no cover - raise ImportError("wolfxl._rust built without a native writer backend") +def _color_to_hex(color: Any) -> str | None: + """Return a normalized RGB value from an openpyxl-compatible color.""" + if color is None: + return None -def _writer_class(rust_module: Any) -> Any: - """Return the current WolfXL writer class, with legacy fallback.""" - - native = getattr(rust_module, "NativeWorkbook", None) - if native is not None: - return native - return getattr(rust_module, "RustXlsxWriterBook") + rgb = getattr(color, "rgb", None) + if isinstance(rgb, str) and len(rgb) >= 6: + return f"#{rgb[2:]}" if len(rgb) == 8 else f"#{rgb}" + + value = getattr(rgb, "value", None) + if isinstance(value, str) and len(value) >= 6: + return f"#{value[2:]}" if len(value) == 8 else f"#{value}" + return None + + +def _col_letter(index: int) -> str: + """Return the one-based column index as an A1 column letter.""" + result = "" + while index > 0: + index, rem = divmod(index - 1, 26) + result = chr(65 + rem) + result + return result + + +def _cell_value_from_wolfxl_cell(cell: Any) -> CellValue: + """Convert a WolfXL cell proxy into ExcelBench's typed value model.""" + value = getattr(cell, "value", None) + if value is None: + return CellValue(type=CellType.BLANK) + if isinstance(value, bool): + return CellValue(type=CellType.BOOLEAN, value=value) + if isinstance(value, (int, float)): + return CellValue(type=CellType.NUMBER, value=value) + if isinstance(value, date) and not isinstance(value, datetime): + return CellValue(type=CellType.DATE, value=value) + if isinstance(value, datetime): + if ( + value.hour == 0 + and value.minute == 0 + and value.second == 0 + and value.microsecond == 0 + ): + return CellValue(type=CellType.DATE, value=value.date()) + return CellValue(type=CellType.DATETIME, value=value) + if isinstance(value, str): + if value in {"#N/A", "#NULL!", "#NAME?", "#REF!"} or ( + value.startswith("#") and value.endswith("!") + ): + return CellValue(type=CellType.ERROR, value=value) + if getattr(cell, "data_type", None) == "f" or value.startswith("="): + formula = value if value.startswith("=") else f"={value}" + if formula in ERROR_FORMULA_MAP: + return CellValue(type=CellType.ERROR, value=ERROR_FORMULA_MAP[formula]) + return CellValue(type=CellType.FORMULA, value=value, formula=formula) + return CellValue(type=CellType.STRING, value=value) + return CellValue(type=CellType.STRING, value=str(value)) def _read_images_from_xlsx(path: Path, sheet_name: str) -> list[JSONDict]: """Read image anchors from OOXML drawing parts. - WolfXL 2.0's public read model exposes cell-level values/styles through - CalamineStyledBook; image metadata still lives in OOXML drawing parts, so - the benchmark adapter reads those parts directly. + WolfXL exposes images through its openpyxl-compatible API, but fixture image + paths remain OOXML package paths. Reading drawing relationships directly + preserves those package-relative paths for ExcelBench comparison. """ - ns = { "main": "http://schemas.openxmlformats.org/spreadsheetml/2006/main", "rel": "http://schemas.openxmlformats.org/package/2006/relationships", @@ -75,13 +109,11 @@ def read_xml(zf: zipfile.ZipFile, name: str) -> ET.Element: def rel_targets(zf: zipfile.ZipFile, rels_path: str) -> dict[str, str]: root = read_xml(zf, rels_path) - out: dict[str, str] = {} - for rel in root.findall("rel:Relationship", ns): - rid = rel.attrib.get("Id") - target = rel.attrib.get("Target") - if rid and target: - out[rid] = target - return out + return { + rel_id: target + for rel in root.findall("rel:Relationship", ns) + if (rel_id := rel.attrib.get("Id")) and (target := rel.attrib.get("Target")) + } def resolve(base_part: str, target: str) -> str: if target.startswith("/"): @@ -93,13 +125,9 @@ def rels_for(part: str) -> str: return posixpath.join(directory, "_rels", f"{filename}.rels") def cell_from_marker(marker: ET.Element) -> str: - col = int(marker.findtext("xdr:col", "0", ns)) + 1 + column = int(marker.findtext("xdr:col", "0", ns)) + 1 row = int(marker.findtext("xdr:row", "0", ns)) + 1 - letters = "" - while col: - col, rem = divmod(col - 1, 26) - letters = chr(65 + rem) + letters - return f"{letters}{row}" + return f"{_col_letter(column)}{row}" with zipfile.ZipFile(path) as zf: workbook = read_xml(zf, "xl/workbook.xml") @@ -108,8 +136,8 @@ def cell_from_marker(marker: ET.Element) -> str: for sheet in workbook.findall("main:sheets/main:sheet", ns): if sheet.attrib.get("name") != sheet_name: continue - rid = sheet.attrib.get(f"{{{ns['r']}}}id") - target = workbook_rels.get(str(rid)) if rid else None + rel_id = sheet.attrib.get(f"{{{ns['r']}}}id") + target = workbook_rels.get(str(rel_id)) if rel_id else None if target: sheet_part = resolve("xl/workbook.xml", target) break @@ -131,7 +159,6 @@ def cell_from_marker(marker: ET.Element) -> str: drawing_rels = rel_targets(zf, rels_for(drawing_part)) except KeyError: drawing_rels = {} - for anchor_tag, anchor_name in ( ("xdr:oneCellAnchor", "oneCell"), ("xdr:twoCellAnchor", "twoCell"), @@ -143,38 +170,79 @@ def cell_from_marker(marker: ET.Element) -> str: continue embed = blip.attrib.get(f"{{{ns['r']}}}embed") media_target = drawing_rels.get(str(embed)) if embed else None - if not media_target: - continue - media_part = resolve(drawing_part, media_target) - images.append( - { - "cell": cell_from_marker(marker), - "path": f"/{media_part}", - "anchor": anchor_name, - } - ) + if media_target: + images.append( + { + "cell": cell_from_marker(marker), + "path": f"/{resolve(drawing_part, media_target)}", + "anchor": anchor_name, + } + ) return images class WolfxlAdapter(ExcelAdapter): - """Hybrid adapter: calamine-styled reads + rust_xlsxwriter writes.""" + """Read and write XLSX workbooks through WolfXL's public Python API.""" def __init__(self) -> None: - # Python-side cell cache: avoids FFI on repeated reads of the same cell. - # Keyed by (workbook_id, sheet, cell) → CellValue. - self._cell_cache: dict[tuple[int, str, str], CellValue] = {} self._workbook_paths: dict[int, Path] = {} + @classmethod + def is_available(cls) -> bool: + """Return whether WolfXL 2's required public API is importable.""" + try: + from wolfxl import ( + Alignment, + Border, + Font, + PatternFill, + Side, + Workbook, + load_workbook, + ) + from wolfxl.chart import BarChart, LineChart, Reference + from wolfxl.comments import Comment + from wolfxl.drawing.image import Image + from wolfxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor + from wolfxl.formatting.rule import ColorScaleRule, DataBarRule, FormulaRule + from wolfxl.worksheet.datavalidation import DataValidation + from wolfxl.worksheet.hyperlink import Hyperlink + from wolfxl.worksheet.table import Table, TableColumn, TableStyleInfo + + required = ( + Alignment, + AnchorMarker, + BarChart, + Border, + ColorScaleRule, + Comment, + DataBarRule, + DataValidation, + Font, + FormulaRule, + Hyperlink, + Image, + LineChart, + PatternFill, + Reference, + Side, + Table, + TableColumn, + TableStyleInfo, + TwoCellAnchor, + Workbook, + load_workbook, + ) + return bool(required) and int(str(wolfxl.__version__).split(".", 1)[0]) >= 2 + except (ImportError, ValueError): + return False + @property def info(self) -> LibraryInfo: - cal_ver = get_rust_backend_version("calamine") - rxw_ver = get_rust_backend_version("rust_xlsxwriter") - if rxw_ver == "unknown": - rxw_ver = get_rust_backend_version("native") return LibraryInfo( name="wolfxl", - version=f"cal={cal_ver}+rxw={rxw_ver}", - language="rust", + version=str(wolfxl.__version__), + language="python", capabilities={"read", "write", "modify"}, ) @@ -183,184 +251,424 @@ def supported_read_extensions(self) -> set[str]: return {".xlsx"} # ========================================================================= - # Read — delegates to CalamineStyledBook + # Read operations # ========================================================================= def open_workbook(self, path: Path) -> Any: - import wolfxl._rust as rust - - m: Any = rust - workbook = getattr(m, "CalamineStyledBook").open(str(path)) + workbook = wolfxl.load_workbook(path, data_only=False) self._workbook_paths[id(workbook)] = path return workbook def close_workbook(self, workbook: Any) -> None: - # Evict cached cells for this workbook. - wb_id = id(workbook) - self._cell_cache = {k: v for k, v in self._cell_cache.items() if k[0] != wb_id} - self._workbook_paths.pop(wb_id, None) + self._workbook_paths.pop(id(workbook), None) + close = getattr(workbook, "close", None) + if callable(close): + close() def get_sheet_names(self, workbook: Any) -> list[str]: - return [str(name) for name in workbook.sheet_names()] - - def read_cell_value(self, workbook: Any, sheet: str, cell: str) -> CellValue: - key = (id(workbook), sheet, cell) - cached = self._cell_cache.get(key) - if cached is not None: - return cached - payload = workbook.read_cell_value(sheet, cell) - if not isinstance(payload, dict): - result = CellValue(type=CellType.STRING, value=str(payload)) - else: - result = cell_value_from_payload(payload) - self._cell_cache[key] = result - return result + return [str(name) for name in workbook.sheetnames] def read_sheet_values( - self, - workbook: Any, - sheet: str, - cell_range: str | None = None, + self, workbook: Any, sheet: str, cell_range: str | None = None ) -> list[list[CellValue]]: - """Bulk read all values from a sheet via CalamineStyledBook.read_sheet_values().""" - raw = workbook.read_sheet_values(sheet, cell_range) - return [ - [ - cell_value_from_payload(v) - if isinstance(v, dict) - else CellValue(type=CellType.BLANK) - for v in row - ] - for row in raw - ] + worksheet = workbook[sheet] + rows = worksheet[cell_range] if cell_range else worksheet.iter_rows() + return [[_cell_value_from_wolfxl_cell(cell) for cell in row] for row in rows] - def read_sheet_values_raw( - self, - workbook: Any, - sheet: str, - cell_range: str | None = None, - ) -> list[list[Any]]: - """Return raw Rust FFI output without cell_value_from_payload() wrapping.""" - result: list[list[Any]] = workbook.read_sheet_values(sheet, cell_range) - return result + def read_cell_value(self, workbook: Any, sheet: str, cell: str) -> CellValue: + return _cell_value_from_wolfxl_cell(workbook[sheet][cell]) def read_cell_format(self, workbook: Any, sheet: str, cell: str) -> CellFormat: - payload = workbook.read_cell_format(sheet, cell) - if not isinstance(payload, dict) or not payload: - return CellFormat() - return dict_to_format(payload) + current = workbook[sheet][cell] + font = current.font + fill = current.fill + alignment = current.alignment + return CellFormat( + bold=font.bold or None, + italic=font.italic or None, + underline=font.underline or None, + strikethrough=font.strike or None, + font_name=font.name or None, + font_size=font.size or None, + font_color=_color_to_hex(getattr(font, "color", None)), + bg_color=( + _color_to_hex(getattr(fill, "fgColor", None)) + if getattr(fill, "patternType", None) == "solid" + else None + ), + number_format=current.number_format or None, + h_align=getattr(alignment, "horizontal", None) or None, + v_align=getattr(alignment, "vertical", None) or None, + wrap=getattr(alignment, "wrap_text", None) or None, + rotation=( + getattr(alignment, "text_rotation", None) + if getattr(alignment, "text_rotation", None) not in (0, None) + else None + ), + indent=getattr(alignment, "indent", None) or None, + ) def read_cell_border(self, workbook: Any, sheet: str, cell: str) -> BorderInfo: - payload = workbook.read_cell_border(sheet, cell) - if not isinstance(payload, dict) or not payload: - return BorderInfo() - return dict_to_border(payload) + border = workbook[sheet][cell].border + + def parse_side(side: Any) -> BorderEdge | None: + if side is None or getattr(side, "style", None) is None: + return None + style_map = { + "thin": BorderStyle.THIN, + "medium": BorderStyle.MEDIUM, + "thick": BorderStyle.THICK, + "double": BorderStyle.DOUBLE, + "dashed": BorderStyle.DASHED, + "dotted": BorderStyle.DOTTED, + "hair": BorderStyle.HAIR, + "mediumDashed": BorderStyle.MEDIUM_DASHED, + "dashDot": BorderStyle.DASH_DOT, + "mediumDashDot": BorderStyle.MEDIUM_DASH_DOT, + "dashDotDot": BorderStyle.DASH_DOT_DOT, + "mediumDashDotDot": BorderStyle.MEDIUM_DASH_DOT_DOT, + "slantDashDot": BorderStyle.SLANT_DASH_DOT, + } + return BorderEdge( + style=style_map.get(side.style, BorderStyle.THIN), + color=_color_to_hex(getattr(side, "color", None)) or "#000000", + ) + + return BorderInfo( + top=parse_side(border.top), + bottom=parse_side(border.bottom), + left=parse_side(border.left), + right=parse_side(border.right), + diagonal_up=parse_side(border.diagonal) if border.diagonalUp else None, + diagonal_down=parse_side(border.diagonal) if border.diagonalDown else None, + ) def read_row_height(self, workbook: Any, sheet: str, row: int) -> float | None: - value = workbook.read_row_height(sheet, row) - if value is None: - return None - if isinstance(value, (int, float)): - return float(value) - return None + height = workbook[sheet].row_dimensions[row].height + return float(height) if isinstance(height, (int, float)) else None def read_column_width(self, workbook: Any, sheet: str, column: str) -> float | None: - value = workbook.read_column_width(sheet, column) - if value is None: + width = workbook[sheet].column_dimensions[column].width + try: + return float(width) if width is not None else None + except (TypeError, ValueError): return None - if isinstance(value, (int, float)): - return float(value) - return None + + # ========================================================================= + # Tier 2 reads + # ========================================================================= def read_merged_ranges(self, workbook: Any, sheet: str) -> list[str]: - result = workbook.read_merged_ranges(sheet) - if isinstance(result, list): - return [str(x) for x in result] - return [] + return [str(cell_range) for cell_range in workbook[sheet].merged_cells.ranges] def read_conditional_formats(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_conditional_formats(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] + conditional_formatting = workbook[sheet].conditional_formatting + rules_by_range = getattr(conditional_formatting, "_cf_rules", None) + if rules_by_range is None: + self.unsupported_operation( + "read_conditional_formats", + "WolfXL's installed compatibility layer does not expose conditional rules.", + ) + rules: list[JSONDict] = [] + for sqref, rule_list in rules_by_range.items(): + range_value = str(getattr(sqref, "sqref", sqref)) + for rule in rule_list: + entry: JSONDict = { + "range": range_value, + "rule_type": getattr(rule, "type", None), + "operator": getattr(rule, "operator", None), + "formula": rule.formula[0] + if getattr(rule, "formula", None) + else None, + "priority": getattr(rule, "priority", None), + "stop_if_true": getattr(rule, "stopIfTrue", None), + "format": {}, + } + dxf = getattr(rule, "dxf", None) + if dxf is not None: + if bg := _color_to_hex( + getattr(getattr(dxf, "fill", None), "fgColor", None) + ): + entry["format"]["bg_color"] = bg + if font_color := _color_to_hex( + getattr(getattr(dxf, "font", None), "color", None) + ): + entry["format"]["font_color"] = font_color + rules.append(entry) + return rules def read_data_validations(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_data_validations(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] - - def read_named_ranges(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_named_ranges(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] - - def read_tables(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_tables(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] + validations = getattr(workbook[sheet].data_validations, "dataValidation", None) + if validations is None: + self.unsupported_operation( + "read_data_validations", + "WolfXL's installed compatibility layer does not expose data validations.", + ) + return [ + { + "range": str(entry.sqref), + "validation_type": entry.type, + "operator": entry.operator or ("between" if entry.formula2 else None), + "formula1": entry.formula1, + "formula2": entry.formula2, + "allow_blank": entry.allow_blank, + "show_input": entry.showInputMessage, + "show_error": entry.showErrorMessage, + "prompt_title": entry.promptTitle, + "prompt": entry.prompt, + "error_title": entry.errorTitle, + "error": entry.error, + } + for entry in validations + ] def read_hyperlinks(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_hyperlinks(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] + links: list[JSONDict] = [] + for row in workbook[sheet].iter_rows(): + for cell in row: + hyperlink = cell.hyperlink + if hyperlink is None: + continue + if hyperlink.target and hyperlink.location: + target = f"{hyperlink.target}#{hyperlink.location}" + internal = False + elif hyperlink.target: + target = hyperlink.target + internal = False + else: + target = hyperlink.location + internal = True + links.append( + { + "cell": cell.coordinate, + "target": target, + "display": cell.value, + "tooltip": hyperlink.tooltip, + "internal": internal, + } + ) + return links def read_images(self, workbook: Any, sheet: str) -> list[JSONDict]: path = self._workbook_paths.get(id(workbook)) if path is None: - return [] - try: - return _read_images_from_xlsx(path, sheet) - except Exception: - return [] + self.unsupported_operation( + "read_images", + "Image package paths are available only for workbooks opened from a file.", + ) + return _read_images_from_xlsx(path, sheet) def read_pivot_tables(self, workbook: Any, sheet: str) -> list[JSONDict]: - return [] + pivots = getattr(workbook[sheet], "pivot_tables", None) + if pivots is None: + self.unsupported_operation( + "read_pivot_tables", + "WolfXL's installed compatibility layer does not expose pivot tables.", + ) + results: list[JSONDict] = [] + for pivot in pivots: + cache = getattr(pivot, "cache", None) + cache_source = getattr(cache, "cacheSource", None) + worksheet_source = getattr(cache_source, "worksheetSource", None) + source_ref = getattr(worksheet_source, "ref", None) + source_sheet = getattr(worksheet_source, "sheet", None) + source_range: str | None + if source_sheet and source_ref: + source_range = f"{source_sheet}!{source_ref}" + else: + source_range = source_ref or getattr(cache_source, "ref", None) + location = getattr(pivot, "location", None) + target_cell = getattr(location, "ref", None) or location + if target_cell and "!" not in str(target_cell): + target_cell = f"{sheet}!{target_cell}" + results.append( + { + "name": getattr(pivot, "name", None), + "source_range": source_range, + "target_cell": target_cell, + } + ) + return results def read_comments(self, workbook: Any, sheet: str) -> list[JSONDict]: - result = workbook.read_comments(sheet) - if isinstance(result, list): - return [dict(x) for x in result if isinstance(x, dict)] - return [] + comments: list[JSONDict] = [] + for row in workbook[sheet].iter_rows(): + for cell in row: + if cell.comment is not None: + comments.append( + { + "cell": cell.coordinate, + "text": cell.comment.text, + "author": cell.comment.author, + "threaded": False, + } + ) + return comments def read_freeze_panes(self, workbook: Any, sheet: str) -> JSONDict: - return dict(workbook.read_freeze_panes(sheet)) + worksheet = workbook[sheet] + result: JSONDict = {} + if worksheet.freeze_panes: + result["mode"] = "freeze" + result["top_left_cell"] = str(worksheet.freeze_panes) + pane = getattr(worksheet.sheet_view, "pane", None) + if pane is not None and pane.state == "split" and (pane.xSplit or pane.ySplit): + result["mode"] = "split" + result["x_split"] = int(pane.xSplit) if pane.xSplit is not None else None + result["y_split"] = int(pane.ySplit) if pane.ySplit is not None else None + if pane.topLeftCell: + result["top_left_cell"] = pane.topLeftCell + if pane.activePane: + result["active_pane"] = pane.activePane + return result # ========================================================================= - # Write — delegates to NativeWorkbook (WolfXL 2.0+) or RustXlsxWriterBook - # on older WolfXL releases. + # Tier 3 reads # ========================================================================= - def create_workbook(self) -> Any: - import wolfxl._rust as rust + def read_named_ranges(self, workbook: Any, sheet: str) -> list[JSONDict]: + def normalize_refers_to(value: Any) -> str: + raw = str(value or "").lstrip("=") + if "!" not in raw: + return raw + sheet_name, address = raw.split("!", 1) + if sheet_name.startswith("'") and sheet_name.endswith("'"): + sheet_name = sheet_name[1:-1].replace("''", "'") + return f"{sheet_name}!{address}" + + results: list[JSONDict] = [] + seen: set[tuple[str, str, str]] = set() + worksheet = workbook[sheet] + sheet_id = workbook.worksheets.index(worksheet) + for key in workbook.defined_names: + name = workbook.defined_names.get(key) + if name is None: + continue + local_sheet_id = getattr(name, "localSheetId", None) + if local_sheet_id is not None and int(local_sheet_id) != sheet_id: + continue + scope = "sheet" if local_sheet_id is not None else "workbook" + item: JSONDict = { + "name": str(getattr(name, "name", key)), + "scope": scope, + "refers_to": normalize_refers_to(getattr(name, "attr_text", None)), + } + signature = (str(item["name"]), str(item["scope"]), str(item["refers_to"])) + if signature not in seen: + seen.add(signature) + results.append(item) + for key in worksheet.defined_names: + name = worksheet.defined_names.get(key) + if name is None: + continue + item = { + "name": str(getattr(name, "name", key)), + "scope": "sheet", + "refers_to": normalize_refers_to(getattr(name, "attr_text", None)), + } + signature = (str(item["name"]), str(item["scope"]), str(item["refers_to"])) + if signature not in seen: + seen.add(signature) + results.append(item) + return results - m: Any = rust - return _writer_class(m)() + def read_tables(self, workbook: Any, sheet: str) -> list[JSONDict]: + worksheet = workbook[sheet] + tables = getattr(worksheet, "tables", None) + if tables is None: + self.unsupported_operation( + "read_tables", + "WolfXL's installed compatibility layer does not expose tables.", + ) + results: list[JSONDict] = [] + for table in tables.values(): + columns = [ + str(column.name) + for column in (getattr(table, "tableColumns", []) or []) + if column.name is not None + ] + if not columns: + from wolfxl.utils.cell import range_boundaries + + boundaries = range_boundaries(str(table.ref)) + min_col = int(boundaries[0] or 0) + min_row = int(boundaries[1] or 0) + max_col = int(boundaries[2] or 0) + columns = [ + "" + if worksheet.cell(row=min_row, column=column).value is None + else str(worksheet.cell(row=min_row, column=column).value) + for column in range(min_col, max_col + 1) + ] + results.append( + { + "name": getattr(table, "displayName", None) + or getattr(table, "name", None), + "ref": getattr(table, "ref", None), + "header_row": getattr(table, "headerRowCount", 1) != 0, + "totals_row": (getattr(table, "totalsRowCount", 0) or 0) > 0, + "style": ( + table.tableStyleInfo.name + if getattr(table, "tableStyleInfo", None) + else None + ), + "columns": columns, + "autofilter": getattr(table, "autoFilter", None) is not None, + } + ) + return results - def add_sheet(self, workbook: Any, name: str) -> None: - workbook.add_sheet(name) + # ========================================================================= + # Write operations + # ========================================================================= - def write_cell_value(self, workbook: Any, sheet: str, cell: str, value: CellValue) -> None: - payload = payload_from_cell_value(value) - workbook.write_cell_value(sheet, cell, payload) + def create_workbook(self) -> Any: + workbook = wolfxl.Workbook() + if workbook.sheetnames: + workbook.remove(workbook.active) + return workbook + + def add_sheet(self, workbook: Any, name: str) -> None: + workbook.create_sheet(name) def write_sheet_values( - self, - workbook: Any, - sheet: str, - start_cell: str, - values: list[list[Any]], + self, workbook: Any, sheet: str, start_cell: str, values: list[list[Any]] ) -> None: - """Bulk write a grid of values via the native writer.""" - workbook.write_sheet_values(sheet, start_cell, values) + from wolfxl.utils.cell import column_index_from_string, coordinate_from_string + + column, row = coordinate_from_string(start_cell) + worksheet = workbook[sheet] + start_column = column_index_from_string(column) + for row_offset, values_row in enumerate(values): + for column_offset, value in enumerate(values_row): + if value is not None: + worksheet.cell( + row=row + row_offset, + column=start_column + column_offset, + value=value, + ) - def write_cell_format(self, workbook: Any, sheet: str, cell: str, format: CellFormat) -> None: - d = format_to_dict(format) - if d: - workbook.write_cell_format(sheet, cell, d) + def write_cell_value( + self, workbook: Any, sheet: str, cell: str, value: CellValue + ) -> None: + target = workbook[sheet][cell] + if value.type == CellType.BLANK: + target.value = None + elif value.type == CellType.FORMULA: + target.value = value.formula or value.value + elif value.type == CellType.ERROR: + error_formulas = { + "#DIV/0!": "=1/0", + "#N/A": "=NA()", + "#VALUE!": '="text"+1', + "#REF!": "=#REF!", + "#NAME?": "=_undefined_name_", + "#NUM!": "=SQRT(-1)", + "#NULL!": "=A1:A2 B1:B2", + } + target.value = error_formulas.get(str(value.value), value.value) + else: + target.value = value.value def write_sheet_formats( self, @@ -369,13 +677,60 @@ def write_sheet_formats( start_cell: str, formats: list[list[dict[str, Any] | None]], ) -> None: - """Bulk write a grid of format dicts via the native writer.""" - workbook.write_sheet_formats(sheet, start_cell, formats) + from wolfxl.utils.cell import column_index_from_string, coordinate_from_string + + column, row = coordinate_from_string(start_cell) + start_column = column_index_from_string(column) + for row_offset, format_row in enumerate(formats): + for column_offset, format_data in enumerate(format_row): + if format_data is not None: + self.write_cell_format( + workbook, + sheet, + f"{_col_letter(start_column + column_offset)}{row + row_offset}", + CellFormat(**format_data), + ) - def write_cell_border(self, workbook: Any, sheet: str, cell: str, border: BorderInfo) -> None: - d = border_to_dict(border) - if d: - workbook.write_cell_border(sheet, cell, d) + def write_cell_format( + self, workbook: Any, sheet: str, cell: str, format: CellFormat + ) -> None: + from wolfxl import Alignment, Color, Font, PatternFill + + target = workbook[sheet][cell] + font_kwargs: JSONDict = {} + for field, attr in ( + ("bold", "bold"), + ("italic", "italic"), + ("underline", "underline"), + ("strikethrough", "strike"), + ("font_name", "name"), + ("font_size", "size"), + ): + if (field_value := getattr(format, field)) is not None: + font_kwargs[attr] = field_value + if format.font_color is not None: + font_kwargs["color"] = Color(rgb=f"FF{format.font_color.lstrip('#')}") + if font_kwargs: + target.font = Font(**font_kwargs) + if format.bg_color is not None: + color = f"FF{format.bg_color.lstrip('#')}" + target.fill = PatternFill( + start_color=color, end_color=color, fill_type="solid" + ) + if format.number_format is not None: + target.number_format = format.number_format + alignment_kwargs: JSONDict = {} + for field, attr in ( + ("h_align", "horizontal"), + ("v_align", "vertical"), + ("wrap", "wrap_text"), + ("rotation", "text_rotation"), + ("indent", "indent"), + ): + if (field_value := getattr(format, field)) is not None: + alignment_kwargs[attr] = field_value + if alignment_kwargs: + target.alignment = Alignment(**alignment_kwargs) def write_sheet_borders( self, @@ -384,64 +739,442 @@ def write_sheet_borders( start_cell: str, borders: list[list[dict[str, Any] | None]], ) -> None: - """Bulk write a grid of border dicts via the native writer.""" - workbook.write_sheet_borders(sheet, start_cell, borders) + from wolfxl.utils.cell import column_index_from_string, coordinate_from_string + + from excelbench.harness.adapters.rust_adapter_utils import dict_to_border + + column, row = coordinate_from_string(start_cell) + start_column = column_index_from_string(column) + for row_offset, border_row in enumerate(borders): + for column_offset, border_data in enumerate(border_row): + if border_data is not None: + self.write_cell_border( + workbook, + sheet, + f"{_col_letter(start_column + column_offset)}{row + row_offset}", + dict_to_border(border_data), + ) - def set_row_height(self, workbook: Any, sheet: str, row: int, height: float) -> None: - workbook.set_row_height(sheet, rust_xlsxwriter_row_index(row), height) + def write_cell_border( + self, workbook: Any, sheet: str, cell: str, border: BorderInfo + ) -> None: + from wolfxl import Border, Color, Side + + def make_side(edge: BorderEdge | None) -> Any: + if edge is None: + return Side() + style_map = { + BorderStyle.NONE: None, + BorderStyle.THIN: "thin", + BorderStyle.MEDIUM: "medium", + BorderStyle.THICK: "thick", + BorderStyle.DOUBLE: "double", + BorderStyle.DASHED: "dashed", + BorderStyle.DOTTED: "dotted", + BorderStyle.HAIR: "hair", + BorderStyle.MEDIUM_DASHED: "mediumDashed", + BorderStyle.DASH_DOT: "dashDot", + BorderStyle.MEDIUM_DASH_DOT: "mediumDashDot", + BorderStyle.DASH_DOT_DOT: "dashDotDot", + BorderStyle.MEDIUM_DASH_DOT_DOT: "mediumDashDotDot", + BorderStyle.SLANT_DASH_DOT: "slantDashDot", + } + style = style_map.get(edge.style) + return ( + Side() + if style is None + else Side(style=style, color=Color(rgb=f"FF{edge.color.lstrip('#')}")) + ) + + diagonal = make_side(border.diagonal_up or border.diagonal_down) + workbook[sheet][cell].border = Border( + left=make_side(border.left), + right=make_side(border.right), + top=make_side(border.top), + bottom=make_side(border.bottom), + diagonal=diagonal, + diagonalUp=border.diagonal_up is not None, + diagonalDown=border.diagonal_down is not None, + ) + + def set_row_height( + self, workbook: Any, sheet: str, row: int, height: float + ) -> None: + workbook[sheet].row_dimensions[row].height = height - def set_column_width(self, workbook: Any, sheet: str, column: str, width: float) -> None: - workbook.set_column_width(sheet, column, width) + def set_column_width( + self, workbook: Any, sheet: str, column: str, width: float + ) -> None: + workbook[sheet].column_dimensions[column].width = width + + # ========================================================================= + # Tier 2 writes + # ========================================================================= def merge_cells(self, workbook: Any, sheet: str, cell_range: str) -> None: - workbook.merge_cells(sheet, cell_range) + workbook[sheet].merge_cells(cell_range) def add_conditional_format(self, workbook: Any, sheet: str, rule: JSONDict) -> None: - workbook.add_conditional_format(sheet, rule.get("cf_rule", rule)) - - def add_data_validation(self, workbook: Any, sheet: str, validation: JSONDict) -> None: - workbook.add_data_validation(sheet, validation) + from wolfxl import Font, PatternFill + from wolfxl.formatting.rule import ( + CellIsRule, + ColorScaleRule, + DataBarRule, + FormulaRule, + ) - def add_named_range(self, workbook: Any, sheet: str, named_range: JSONDict) -> None: - workbook.add_named_range(sheet, named_range) + cfg = rule.get("cf_rule", rule) + range_ref = cfg.get("range") + if not isinstance(range_ref, str): + raise ValueError("add_conditional_format requires range") + fmt = cfg.get("format") or {} + fill = ( + PatternFill( + start_color=f"FF{str(fmt['bg_color']).lstrip('#')}", + end_color=f"FF{str(fmt['bg_color']).lstrip('#')}", + fill_type="solid", + ) + if fmt.get("bg_color") + else None + ) + font = ( + Font(color=f"FF{str(fmt['font_color']).lstrip('#')}") + if fmt.get("font_color") + else None + ) + rule_type = cfg.get("rule_type") + formula = cfg.get("formula") + if rule_type in {"cellIs", "cellIsRule"}: + rule_obj: Any = CellIsRule( + operator=cfg.get("operator"), + formula=[str(formula)], + fill=fill, + font=font, + stopIfTrue=cfg.get("stop_if_true", False), + ) + elif rule_type in {"expression", "formula"}: + rule_obj = FormulaRule( + formula=[str(formula)], + fill=fill, + font=font, + stopIfTrue=cfg.get("stop_if_true", False), + ) + elif rule_type == "colorScale": + rule_obj = ColorScaleRule( + start_type="min", + start_color="FFAA0000", + mid_type="percentile", + mid_value=50, + mid_color="FFFFFF00", + end_type="max", + end_color="FF00AA00", + ) + elif rule_type == "dataBar": + rule_obj = DataBarRule( + start_type="min", end_type="max", color="FF638EC6", showValue=True + ) + else: + self.unsupported_operation( + "add_conditional_format", + f"WolfXL adapter does not support rule type {rule_type!r}.", + ) + if cfg.get("priority") is not None: + rule_obj.priority = cfg["priority"] + workbook[sheet].conditional_formatting.add(range_ref, rule_obj) - def add_table(self, workbook: Any, sheet: str, table: JSONDict) -> None: - workbook.add_table(sheet, table.get("table", table)) + def add_data_validation( + self, workbook: Any, sheet: str, validation: JSONDict + ) -> None: + from wolfxl.worksheet.datavalidation import DataValidation + + cfg = validation.get("validation", validation) + cell_range = cfg.get("range") + if not isinstance(cell_range, str): + raise ValueError("add_data_validation requires range") + data_validation = DataValidation( + type=cfg.get("validation_type"), + operator=cfg.get("operator"), + formula1=cfg.get("formula1"), + formula2=cfg.get("formula2"), + allow_blank=cfg.get("allow_blank"), + showInputMessage=cfg.get("show_input"), + showErrorMessage=cfg.get("show_error"), + promptTitle=cfg.get("prompt_title"), + prompt=cfg.get("prompt"), + errorTitle=cfg.get("error_title"), + error=cfg.get("error"), + ) + workbook[sheet].add_data_validation(data_validation) + data_validation.add(cell_range) def add_hyperlink(self, workbook: Any, sheet: str, link: JSONDict) -> None: - link_data = link.get("hyperlink", link) - cell = link_data.get("cell") - display = link_data.get("display") or link_data.get("target") - if isinstance(cell, str) and display is not None: - self.write_cell_value( - workbook, - sheet, - cell, - CellValue(type=CellType.STRING, value=str(display)), + from wolfxl.worksheet.hyperlink import Hyperlink + + cfg = link.get("hyperlink", link) + cell = cfg.get("cell") + if not isinstance(cell, str): + raise ValueError("add_hyperlink requires cell") + target = cfg.get("target") + current = workbook[sheet][cell] + if cfg.get("display") is not None: + current.value = cfg["display"] + if cfg.get("internal"): + current.hyperlink = Hyperlink( + ref=cell, location=str(target).lstrip("#") if target else None + ) + else: + current.hyperlink = Hyperlink( + ref=cell, target=str(target) if target else None ) - workbook.add_hyperlink(sheet, link_data) + if current.hyperlink is not None and cfg.get("tooltip") is not None: + current.hyperlink.tooltip = str(cfg["tooltip"]) def add_image(self, workbook: Any, sheet: str, image: JSONDict) -> None: - image_data = image.get("image", image) - path = image_data.get("path") - if not isinstance(path, str): - return - from wolfxl._images import image_to_writer_payload from wolfxl.drawing.image import Image - img = Image(path) - anchor = image_data.get("cell") or "A1" - img.anchor = str(anchor) - workbook.add_image(sheet, image_to_writer_payload(img)) + cfg = image.get("image", image) + path = cfg.get("path") + cell = cfg.get("cell") + if not isinstance(path, str) or not isinstance(cell, str): + raise ValueError("add_image requires path and cell") + workbook[sheet].add_image(Image(path), cell) def add_pivot_table(self, workbook: Any, sheet: str, pivot: JSONDict) -> None: - raise NotImplementedError("wolfxl pivot tables not implemented") + self.unsupported_operation( + "add_pivot_table", + ( + "WolfXL requires a concrete registered pivot cache; ExcelBench's " + "generic pivot payload cannot construct one." + ), + ) def add_comment(self, workbook: Any, sheet: str, comment: JSONDict) -> None: - workbook.add_comment(sheet, comment) + from wolfxl.comments import Comment + + cfg = comment.get("comment", comment) + cell = cfg.get("cell") + text = cfg.get("text") + if not isinstance(cell, str) or text is None: + raise ValueError("add_comment requires cell and text") + workbook[sheet][cell].comment = Comment(str(text), str(cfg.get("author") or "")) + + def add_named_range(self, workbook: Any, sheet: str, named_range: JSONDict) -> None: + from wolfxl.workbook.defined_name import DefinedName + + cfg = named_range.get("named_range", named_range) + name = cfg.get("name") + refers_to = cfg.get("refers_to") + if not isinstance(name, str) or not isinstance(refers_to, str): + raise ValueError("add_named_range requires name and refers_to") + defined_name = DefinedName( + name, attr_text=refers_to if refers_to.startswith("=") else f"={refers_to}" + ) + if cfg.get("scope", "workbook") == "sheet": + workbook[sheet].defined_names.add(defined_name) + else: + workbook.defined_names.add(defined_name) + + def add_table(self, workbook: Any, sheet: str, table: JSONDict) -> None: + from wolfxl.worksheet.filters import AutoFilter + from wolfxl.worksheet.table import Table, TableColumn, TableStyleInfo + + cfg = table.get("table", table) + name = cfg.get("name") + cell_range = cfg.get("ref") + if not isinstance(name, str) or not isinstance(cell_range, str): + raise ValueError("add_table requires name and ref") + result = Table(displayName=name, ref=cell_range) + if cfg.get("header_row") is False: + result.headerRowCount = 0 + if cfg.get("totals_row"): + result.totalsRowCount = 1 + if (style_name := cfg.get("style")) is not None: + result.tableStyleInfo = TableStyleInfo( + name=str(style_name), + showFirstColumn=False, + showLastColumn=False, + showRowStripes=True, + showColumnStripes=False, + ) + columns = cfg.get("columns") + if isinstance(columns, list) and columns: + result.tableColumns = [ + TableColumn(id=index, name=str(column)) + for index, column in enumerate(columns, start=1) + ] + if cfg.get("autofilter"): + result.autoFilter = AutoFilter(ref=cell_range) + workbook[sheet].add_table(result) def set_freeze_panes(self, workbook: Any, sheet: str, settings: JSONDict) -> None: - workbook.set_freeze_panes(sheet, settings) + cfg = settings.get("freeze", settings) + worksheet = workbook[sheet] + if cfg.get("mode") == "freeze": + worksheet.freeze_panes = cfg.get("top_left_cell") + return + if cfg.get("mode") == "split": + from wolfxl.worksheet.views import Pane + + worksheet.freeze_panes = None + pane = worksheet.sheet_view.pane or Pane() + worksheet.sheet_view.pane = pane + if cfg.get("x_split") is not None: + pane.xSplit = cfg["x_split"] + if cfg.get("y_split") is not None: + pane.ySplit = cfg["y_split"] + if cfg.get("top_left_cell") is not None: + pane.topLeftCell = cfg["top_left_cell"] + if cfg.get("active_pane") is not None: + pane.activePane = cfg["active_pane"] + pane.state = "split" + + # ========================================================================= + # Tier 4 operations + # ========================================================================= + + def read_sheet_protection(self, workbook: Any, sheet: str) -> JSONDict: + protection = workbook[sheet].protection + return { + "protected": bool(protection.sheet), + "password_hash_present": bool(protection.password or protection.hashValue), + "format_cells": protection.formatCells, + "insert_rows": protection.insertRows, + "select_locked_cells": protection.selectLockedCells, + "select_unlocked_cells": protection.selectUnlockedCells, + "sort": protection.sort, + "auto_filter": protection.autoFilter, + } + + def set_sheet_protection( + self, workbook: Any, sheet: str, settings: JSONDict + ) -> None: + cfg = settings.get("protection", settings) + protection = workbook[sheet].protection + for key, attr in ( + ("protected", "sheet"), + ("format_cells", "formatCells"), + ("insert_rows", "insertRows"), + ("select_locked_cells", "selectLockedCells"), + ("select_unlocked_cells", "selectUnlockedCells"), + ("sort", "sort"), + ("auto_filter", "autoFilter"), + ): + if cfg.get(key) is not None: + setattr(protection, attr, bool(cfg[key])) + if cfg.get("password"): + protection.set_password(str(cfg["password"])) + + def read_page_setup(self, workbook: Any, sheet: str) -> JSONDict: + worksheet = workbook[sheet] + page_setup = worksheet.page_setup + return { + "orientation": page_setup.orientation, + "fit_to_width": page_setup.fitToWidth, + "fit_to_height": page_setup.fitToHeight, + "scale": page_setup.scale, + "print_title_rows": worksheet.print_title_rows, + "header_center": worksheet.oddHeader.center.text, + "footer_center": worksheet.oddFooter.center.text, + } + + def set_page_setup(self, workbook: Any, sheet: str, settings: JSONDict) -> None: + cfg = settings.get("page_setup", settings) + worksheet = workbook[sheet] + page_setup = worksheet.page_setup + if cfg.get("orientation") is not None: + page_setup.orientation = str(cfg["orientation"]) + if cfg.get("fit_to_width") is not None: + page_setup.fitToWidth = int(cfg["fit_to_width"]) + if cfg.get("fit_to_height") is not None: + page_setup.fitToHeight = int(cfg["fit_to_height"]) + if cfg.get("scale") is not None: + page_setup.scale = int(cfg["scale"]) + if cfg.get("print_title_rows") is not None: + # WolfXL 2.1's public setter accepts the unanchored openpyxl + # compatibility spelling ("1:2"), while ExcelBench's contract + # uses the OOXML-style "$1:$2". + worksheet.print_title_rows = str(cfg["print_title_rows"]).replace("$", "") + if cfg.get("header_center") is not None: + worksheet.oddHeader.center.text = str(cfg["header_center"]) + if cfg.get("footer_center") is not None: + worksheet.oddFooter.center.text = str(cfg["footer_center"]) + + def read_chart_anchors(self, workbook: Any, sheet: str) -> list[JSONDict]: + def cell_from_marker(marker: Any) -> str | None: + if marker is None: + return None + return f"{_col_letter(marker.col + 1)}{marker.row + 1}" + + charts = getattr(workbook[sheet], "_charts", None) + if charts is None: + self.unsupported_operation( + "read_chart_anchors", + "WolfXL's installed compatibility layer does not expose charts.", + ) + results: list[JSONDict] = [] + for chart in charts: + anchor = getattr(chart, "anchor", None) + # In WolfXL 2.1 a loaded chart's public anchor is its default + # placement cell, while the persisted DrawingML anchor is retained + # in the openpyxl-compatible private _anchor field. + if isinstance(anchor, str): + anchor = getattr(chart, "_anchor", None) + anchor_name = type(anchor).__name__ if anchor is not None else "" + results.append( + { + "type": type(chart).__name__.replace("Chart", "").lower() or None, + "anchor_type": ( + "twoCell" + if anchor_name == "TwoCellAnchor" + else "oneCell" + if anchor_name == "OneCellAnchor" + else "absolute" + if anchor_name == "AbsoluteAnchor" + else None + ), + "from": cell_from_marker(getattr(anchor, "_from", None)), + "to": cell_from_marker(getattr(anchor, "to", None)) + if anchor_name == "TwoCellAnchor" + else None, + } + ) + return results + + def add_chart_with_anchor(self, workbook: Any, sheet: str, chart: JSONDict) -> None: + from wolfxl.chart import BarChart, LineChart, Reference + from wolfxl.drawing.spreadsheet_drawing import AnchorMarker, TwoCellAnchor + from wolfxl.utils.cell import coordinate_to_tuple + + cfg = chart.get("chart", chart) + data_ref = cfg.get("data_ref") + if not isinstance(data_ref, str) or not data_ref: + raise ValueError("add_chart_with_anchor requires data_ref") + worksheet = workbook[sheet] + series_chart: Any = ( + LineChart() if str(cfg.get("type", "bar")).lower() == "line" else BarChart() + ) + qualified_data_ref = ( + data_ref if "!" in data_ref else f"{worksheet.title}!{data_ref}" + ) + series_chart.add_data( + Reference(worksheet, range_string=qualified_data_ref), + titles_from_data=False, + ) + if (categories_ref := cfg.get("categories_ref")) is not None: + categories = str(categories_ref) + qualified_categories = ( + categories if "!" in categories else f"{worksheet.title}!{categories}" + ) + series_chart.set_categories( + Reference(worksheet, range_string=qualified_categories) + ) + from_row, from_column = coordinate_to_tuple(str(cfg.get("from") or "B2")) + to_row, to_column = coordinate_to_tuple(str(cfg.get("to") or "H12")) + series_chart.anchor = TwoCellAnchor( + _from=AnchorMarker(col=from_column - 1, row=from_row - 1), + to=AnchorMarker(col=to_column - 1, row=to_row - 1), + ) + worksheet.add_chart(series_chart) def save_workbook(self, workbook: Any, path: Path) -> None: - workbook.save(str(path)) + workbook.save(path) diff --git a/src/excelbench/harness/adapters/zavora_adapter.py b/src/excelbench/harness/adapters/zavora_adapter.py new file mode 100644 index 0000000..6bc6656 --- /dev/null +++ b/src/excelbench/harness/adapters/zavora_adapter.py @@ -0,0 +1,331 @@ +"""Write-oriented adapter backed by the Zavora external helper.""" + +from __future__ import annotations + +from dataclasses import asdict +from pathlib import Path +from typing import Any + +from excelbench.harness.adapters.base import WriteOnlyAdapter +from excelbench.harness.external_oracles import ( + ExternalOracleRequest, + ExternalOracleTool, + external_oracle_catalog, + run_external_oracle, +) +from excelbench.models import BorderInfo, CellFormat, CellType, CellValue, LibraryInfo + +WorkbookData = dict[str, Any] + + +class ZavoraAdapter(WriteOnlyAdapter): + """Cross-language write-first adapter backed by the Zavora Rust helper.""" + + @classmethod + def repo_root(cls) -> Path: + return Path(__file__).resolve().parents[4] + + @classmethod + def tool(cls) -> ExternalOracleTool: + return external_oracle_catalog(repo_root=cls.repo_root())["zavora"] + + @classmethod + def is_available(cls) -> bool: + return cls.tool().is_available() + + @property + def info(self) -> LibraryInfo: + return LibraryInfo( + name="zavora-xlsx", + version="0.1.2", + language="rust", + capabilities={"write"}, + ) + + def create_workbook(self) -> WorkbookData: + return { + "sheets": [], + "cells": [], + "formats": [], + "borders": [], + "columns": [], + "row_heights": [], + "merges": [], + "validations": [], + "hyperlinks": [], + "comments": [], + "panes": [], + "named_ranges": [], + "tables": [], + "conditional_formats": [], + "charts": [], + "pivots": [], + "slicers": [], + "pictures": [], + } + + def add_sheet(self, workbook: WorkbookData, name: str) -> None: + if not any(sheet["name"] == name for sheet in workbook["sheets"]): + workbook["sheets"].append({"name": name}) + + def _ensure_sheet(self, workbook: WorkbookData, sheet: str) -> None: + self.add_sheet(workbook, sheet) + + def write_cell_value( + self, + workbook: WorkbookData, + sheet: str, + cell: str, + value: CellValue, + ) -> None: + self._ensure_sheet(workbook, sheet) + entry: dict[str, Any] = {"sheet": sheet, "cell": cell} + if value.type == CellType.FORMULA: + entry["type"] = "formula" + entry["formula"] = value.formula or str(value.value or "") + entry["value"] = value.value + elif value.type == CellType.BLANK or ( + value.type == CellType.STRING and value.value == "" + ): + entry["type"] = "blank" + entry["value"] = None + else: + entry["type"] = str(value.type) + entry["value"] = self._serialize_value(value) + workbook["cells"].append(entry) + + def write_cell_format( + self, + workbook: WorkbookData, + sheet: str, + cell: str, + format: CellFormat, + ) -> None: + self._ensure_sheet(workbook, sheet) + workbook["formats"].append( + { + "sheet": sheet, + "cell": cell, + "bold": format.bold, + "italic": format.italic, + "underline": format.underline, + "strikethrough": format.strikethrough, + "font_name": format.font_name, + "font_size": format.font_size, + "font_color": format.font_color, + "bg_color": format.bg_color, + "number_format": format.number_format, + "h_align": format.h_align, + "v_align": format.v_align, + "wrap": format.wrap, + "rotation": format.rotation, + "indent": format.indent, + } + ) + + def write_cell_border( + self, + workbook: WorkbookData, + sheet: str, + cell: str, + border: BorderInfo, + ) -> None: + self._ensure_sheet(workbook, sheet) + workbook["borders"].append( + {"sheet": sheet, "cell": cell, "border": asdict(border)} + ) + + def set_row_height( + self, + workbook: WorkbookData, + sheet: str, + row: int, + height: float, + ) -> None: + self._ensure_sheet(workbook, sheet) + workbook["row_heights"].append({"sheet": sheet, "row": row, "height": height}) + + def set_column_width( + self, + workbook: WorkbookData, + sheet: str, + column: str, + width: float, + ) -> None: + self._ensure_sheet(workbook, sheet) + workbook["columns"].append( + {"sheet": sheet, "start": column, "end": column, "width": width} + ) + + def merge_cells(self, workbook: WorkbookData, sheet: str, cell_range: str) -> None: + self._ensure_sheet(workbook, sheet) + workbook["merges"].append({"sheet": sheet, "range": cell_range}) + + def add_conditional_format( + self, workbook: WorkbookData, sheet: str, rule: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = rule.get("cf_rule", rule) + workbook["conditional_formats"].append( + { + "sheet": sheet, + "range": payload.get("range"), + "type": self._map_conditional_format_type(payload.get("rule_type")), + "criteria": self._map_conditional_format_criteria( + payload.get("rule_type"), + payload.get("operator"), + payload.get("formula"), + ), + "value": self._map_conditional_format_value(payload), + "stop_if_true": payload.get("stop_if_true", False), + "bg_color": (payload.get("format") or {}).get("bg_color", ""), + } + ) + + def add_data_validation( + self, workbook: WorkbookData, sheet: str, validation: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = validation.get("validation", validation) + workbook["validations"].append({"sheet": sheet, **payload}) + + def add_hyperlink( + self, workbook: WorkbookData, sheet: str, link: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = link.get("hyperlink", link) + workbook["hyperlinks"].append({"sheet": sheet, **payload}) + + def add_image( + self, workbook: WorkbookData, sheet: str, image: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = image.get("image", image) + workbook["pictures"].append({"sheet": sheet, **payload}) + + def add_pivot_table( + self, workbook: WorkbookData, sheet: str, pivot: dict[str, Any] + ) -> None: + payload = pivot.get("pivot", pivot) + target_cell = payload.get("target_cell") + target_range = payload.get("range") + if target_range is None and target_cell is not None: + target_range = f"{sheet}!{target_cell}:{target_cell}" + workbook["pivots"].append( + { + "data_range": payload.get("source_range") or payload.get("data_range"), + "range": target_range, + "name": payload.get("name"), + "rows": payload.get("rows") + or [{"name": name} for name in payload.get("row_fields", [])], + "columns": payload.get("columns") + or [{"name": name} for name in payload.get("column_fields", [])], + "data": payload.get("data") + or [ + {"name": name, "subtotal": "Sum"} + for name in payload.get("data_fields", []) + ], + "filters": payload.get("filters") + or [{"name": name} for name in payload.get("filter_fields", [])], + } + ) + + def add_comment( + self, workbook: WorkbookData, sheet: str, comment: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = comment.get("comment", comment) + workbook["comments"].append({"sheet": sheet, **payload}) + + def set_freeze_panes( + self, workbook: WorkbookData, sheet: str, settings: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = settings.get("freeze", settings) + workbook["panes"].append({"sheet": sheet, **payload}) + + def add_table( + self, workbook: WorkbookData, sheet: str, table: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = table.get("table", table) + workbook["tables"].append( + { + "sheet": sheet, + "range": payload.get("ref") or payload.get("range"), + "name": payload.get("name"), + "style": payload.get("style"), + "show_header_row": payload.get("header_row", True), + "show_row_stripes": True, + "totals_row": payload.get("totals_row", False), + "columns": payload.get("columns", []), + "autofilter": payload.get("autofilter", False), + } + ) + + def add_named_range( + self, workbook: WorkbookData, sheet: str, named_range: dict[str, Any] + ) -> None: + self._ensure_sheet(workbook, sheet) + payload = named_range.get("named_range", named_range) + workbook["named_ranges"].append({"sheet": sheet, **payload}) + + def save_workbook(self, workbook: WorkbookData, path: Path) -> None: + result = run_external_oracle( + self.tool(), + ExternalOracleRequest( + fixture_id="zavora-adapter", + operation="write_fixture", + output_path=path, + payload=workbook, + ), + timeout_seconds=300, + ) + if result.skipped: + raise FileNotFoundError(result.notes or "Zavora helper unavailable") + if not result.passed: + message = result.payload.get("message") or result.stderr or result.stdout + raise RuntimeError(str(message)) + + def _serialize_value(self, value: CellValue) -> Any: + if value.type == CellType.BLANK: + return None + if value.type == CellType.DATE and value.value is not None: + return value.value.isoformat() + if value.type == CellType.DATETIME and value.value is not None: + return value.value.isoformat(timespec="seconds") + return value.value + + def _map_conditional_format_type(self, value: Any) -> str: + rule_type = str(value or "") + if rule_type == "colorScale": + return "3_color_scale" + if rule_type == "dataBar": + return "data_bar" + if rule_type == "iconSet": + return "icon_set" + if rule_type == "expression": + return "formula" + return "cell" + + def _map_conditional_format_criteria( + self, rule_type: Any, operator: Any, formula: Any + ) -> str: + if str(rule_type or "") == "expression": + return str(formula or "").lstrip("=") + mapping = { + "greaterThan": ">", + "greaterThanOrEqual": ">=", + "lessThan": "<", + "lessThanOrEqual": "<=", + "equal": "==", + "notEqual": "!=", + "between": "between", + "notBetween": "not between", + } + return mapping.get(str(operator or ""), ">") + + def _map_conditional_format_value(self, payload: dict[str, Any]) -> str: + if str(payload.get("rule_type") or "") == "expression": + return "" + return (payload.get("formula") or payload.get("value") or "0").lstrip("=") diff --git a/src/excelbench/harness/calc.py b/src/excelbench/harness/calc.py new file mode 100644 index 0000000..69250e6 --- /dev/null +++ b/src/excelbench/harness/calc.py @@ -0,0 +1,456 @@ +"""Formula recalculation engines and oracle-backed comparison for ExcelBench.""" + +from __future__ import annotations + +import json +import math +import shutil +import subprocess +import tempfile +from collections.abc import Mapping +from pathlib import Path +from typing import Any, Protocol + +from openpyxl import load_workbook + +from excelbench.harness.external_oracles import ( + ExternalOracleRequest, + external_oracle_catalog, + run_external_oracle, +) +from excelbench.results.calc_renderer import render_calc_results + +SOFFICE_PATH = Path( + shutil.which("soffice") or "/opt/homebrew/bin/soffice" +) + + +class CalcEngine(Protocol): + """Protocol implemented by a spreadsheet formula recalculation engine.""" + + name: str + + def available(self) -> bool: + """Return whether this engine can run on the current machine.""" + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + """Calculate a workbook and return its formula-cell values.""" + + +def formula_cells(input_path: Path) -> list[str]: + """Return workbook-qualified references for every formula cell in a workbook.""" + workbook = load_workbook(input_path, data_only=False, read_only=True) + try: + return [ + f"{worksheet.title}!{cell.coordinate}" + for worksheet in workbook.worksheets + for row in worksheet.iter_rows() + for cell in row + if isinstance(cell.value, str) and cell.value.startswith("=") + ] + finally: + workbook.close() + + +def libreoffice_version() -> str | None: + """Return LibreOffice's version string when the configured binary is present.""" + if not SOFFICE_PATH.is_file(): + return None + completed = subprocess.run( + [str(SOFFICE_PATH), "--version"], + capture_output=True, + check=False, + text=True, + timeout=30, + ) + if completed.returncode != 0: + return None + version = completed.stdout.strip() or completed.stderr.strip() + return version or None + + +def recalculate_with_libreoffice(input_path: Path, output_path: Path) -> str | None: + """Recalculate ``input_path`` through an isolated headless LibreOffice profile. + + The workbook is copied to a temporary source directory before ``--convert-to + xlsx`` runs, so LibreOffice always writes a distinct file and its calculated + cell caches can be copied to ``output_path`` safely. + """ + if not SOFFICE_PATH.is_file(): + return f"LibreOffice binary not found at {SOFFICE_PATH}" + + output_path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.TemporaryDirectory(prefix="excelbench-libreoffice-") as temporary_dir: + work_dir = Path(temporary_dir) + source_dir = work_dir / "source" + converted_dir = work_dir / "converted" + profile_dir = work_dir / "profile" + source_dir.mkdir() + converted_dir.mkdir() + profile_dir.mkdir() + source_path = source_dir / input_path.name + shutil.copy2(input_path, source_path) + command = [ + str(SOFFICE_PATH), + "--headless", + f"-env:UserInstallation={profile_dir.as_uri()}", + "--convert-to", + "xlsx", + "--outdir", + str(converted_dir), + str(source_path), + ] + try: + completed = subprocess.run( + command, + cwd=work_dir, + capture_output=True, + check=False, + text=True, + timeout=120, + ) + except (OSError, subprocess.TimeoutExpired) as exc: + return f"LibreOffice conversion could not run: {exc}" + if completed.returncode != 0: + detail = (completed.stderr or completed.stdout).strip() or "no diagnostic" + return f"LibreOffice conversion failed: {detail}" + + converted_path = converted_dir / input_path.name + if not converted_path.is_file(): + detail = ( + completed.stderr or completed.stdout + ).strip() or "no output workbook" + return f"LibreOffice conversion produced no XLSX: {detail}" + shutil.copy2(converted_path, output_path) + return None + + +def _read_values( + workbook_path: Path, references: list[str], *, reader: str +) -> dict[str, Any]: + if reader == "wolfxl": + import wolfxl + + workbook = wolfxl.load_workbook(workbook_path, data_only=True) + return { + reference: workbook[sheet_name][cell_reference].value + for reference in references + for sheet_name, cell_reference in [reference.split("!", maxsplit=1)] + } + + workbook = load_workbook(workbook_path, data_only=True, read_only=True) + try: + return { + reference: workbook[sheet_name][cell_reference].value + for reference in references + for sheet_name, cell_reference in [reference.split("!", maxsplit=1)] + } + finally: + workbook.close() + + +class WolfXLCalcEngine: + """Formula calculation through WolfXL's public workbook API.""" + + name = "wolfxl" + + def available(self) -> bool: + """Return whether WolfXL can be imported.""" + try: + import wolfxl # noqa: F401 + except ImportError: + return False + return True + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + """Calculate with WolfXL, save the workbook, and read cached results.""" + try: + import wolfxl + + output_path.parent.mkdir(parents=True, exist_ok=True) + references = formula_cells(input_path) + workbook = wolfxl.load_workbook(input_path) + workbook.calculate() + workbook.save(output_path) + return { + "status": "passed", + "values": _read_values(output_path, references, reader="wolfxl"), + "reason": None, + } + except Exception as exc: # Engine errors are data for the comparison report. + return { + "status": "failed", + "values": {}, + "reason": f"{type(exc).__name__}: {exc}", + } + + +class LibreOfficeCalcEngine: + """Formula calculation through headless LibreOffice conversion.""" + + name = "libreoffice" + + def available(self) -> bool: + """Return whether the configured LibreOffice binary is available.""" + return libreoffice_version() is not None + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + """Calculate with LibreOffice and read cached results from its output.""" + if not self.available(): + return { + "status": "unavailable", + "values": {}, + "reason": f"LibreOffice binary not found at {SOFFICE_PATH}", + } + reason = recalculate_with_libreoffice(input_path, output_path) + if reason is not None: + return {"status": "failed", "values": {}, "reason": reason} + try: + return { + "status": "passed", + "values": _read_values( + output_path, formula_cells(input_path), reader="openpyxl" + ), + "reason": None, + } + except Exception as exc: # Engine errors are data for the comparison report. + return { + "status": "failed", + "values": {}, + "reason": f"{type(exc).__name__}: {exc}", + } + + +class AsposeCellsFossCalcEngine: + """Best-effort evaluation through the intentionally limited FOSS evaluator.""" + + name = "aspose_cells_foss" + + def available(self) -> bool: + """Return whether Aspose.Cells FOSS can be imported.""" + try: + import aspose.cells_foss # noqa: F401 + from aspose.cells_foss.formula_evaluator import FormulaEvaluator # noqa: F401 + except ImportError: + return False + return True + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + """Evaluate every formula with the FOSS evaluator and save its output.""" + try: + from aspose.cells_foss import Workbook + from aspose.cells_foss.formula_evaluator import FormulaEvaluator + + workbook = Workbook(str(input_path)) + evaluator = FormulaEvaluator(workbook) + values: dict[str, Any] = {} + unsupported: list[str] = [] + for worksheet in workbook.worksheets: + for cell_reference, cell in worksheet.cells: + if not isinstance(cell.formula, str) or not cell.formula.startswith( + "=" + ): + continue + value = evaluator.evaluate(cell.formula, worksheet, cell_reference) + reference = f"{worksheet.name}!{cell_reference}" + values[reference] = value + if value is None: + unsupported.append(reference) + output_path.parent.mkdir(parents=True, exist_ok=True) + workbook.save(str(output_path)) + if unsupported: + preview = ", ".join(unsupported[:5]) + return { + "status": "failed", + "values": values, + "reason": ( + "FOSS FormulaEvaluator returned no value for " + f"{len(unsupported)} formulas: {preview}" + ), + } + return {"status": "passed", "values": values, "reason": None} + except Exception as exc: # Its unsupported parser must not escape the suite. + return { + "status": "failed", + "values": {}, + "reason": f"{type(exc).__name__}: {exc}", + } + + +class ZavoraCalcEngine: + """Formula calculation through the optional Zavora external oracle helper.""" + + name = "zavora" + + def available(self) -> bool: + """Return whether the catalogued Zavora helper can be launched.""" + return external_oracle_catalog(_repository_root())["zavora"].is_available() + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + """Delegate calculation to Zavora's JSON external-oracle protocol.""" + tool = external_oracle_catalog(_repository_root())["zavora"] + if not tool.is_available(): + return { + "status": "unavailable", + "values": {}, + "reason": "Zavora helper is unavailable", + } + result = run_external_oracle( + tool, + ExternalOracleRequest( + fixture_id=input_path.stem, + operation="calculate", + payload={}, + input_path=input_path.resolve(), + output_path=output_path.resolve(), + ), + ) + if result.skipped: + return { + "status": "unavailable", + "values": {}, + "reason": result.notes or "Zavora helper skipped", + } + if not result.passed: + detail = ( + result.notes + or result.stderr.strip() + or result.stdout.strip() + or "no diagnostic" + ) + return { + "status": "failed", + "values": {}, + "reason": f"Zavora calculation failed: {detail}", + } + values = result.payload.get("values") + if not isinstance(values, dict): + return { + "status": "failed", + "values": {}, + "reason": "Zavora response omitted values", + } + return {"status": "passed", "values": values, "reason": None} + + +def values_match(expected: Any, actual: Any) -> bool: + """Compare calculation values with number tolerance and exact scalar semantics.""" + if isinstance(expected, bool) or isinstance(actual, bool): + return ( + isinstance(expected, bool) + and isinstance(actual, bool) + and expected is actual + ) + if isinstance(expected, (int, float)) and isinstance(actual, (int, float)): + return math.isclose(float(expected), float(actual), abs_tol=1e-6, rel_tol=1e-9) + return bool(expected == actual) + + +def run_calc_suite( + fixture: Path, expected: dict[str, Any] | Path, output_dir: Path +) -> dict[str, Any]: + """Run available engines against the LibreOffice calculation oracle fixture.""" + expected_data = _load_expected(expected) + expected_cells = expected_data["cells"] + if not isinstance(expected_cells, Mapping): + raise ValueError("Expected calculation data must contain a cells mapping") + + output_dir.mkdir(parents=True, exist_ok=True) + engine_results: dict[str, dict[str, Any]] = {} + for engine in _engines(): + if not engine.available(): + engine_results[engine.name] = { + "status": "unavailable", + "matched": 0, + "total": len(expected_cells), + "mismatched_cells": [], + "reason": f"{engine.name} is unavailable", + } + continue + try: + engine_result = engine.calculate( + fixture, output_dir / engine.name / fixture.name + ) + except Exception as exc: # Engine crashes are comparison data, not aborts. + engine_result = { + "status": "failed", + "values": {}, + "reason": f"{type(exc).__name__}: {exc}", + } + values = engine_result.get("values", {}) + if not isinstance(values, Mapping): + values = {} + matched, mismatches = _compare_expected_values(expected_cells, values) + total = len(expected_cells) + reason: str | None + if engine_result["status"] == "passed" and matched < total: + # An engine that runs but produces wrong or missing values is a + # failed calculation run, not a pass. + status = "failed" + missing = sum(1 for m in mismatches if m.get("actual") is None) + wrong = len(mismatches) - missing + reason = ( + f"{total - matched}/{total} formula values wrong or missing " + f"(first mismatch batch: {len(mismatches)} shown, " + f"{missing} missing, {wrong} wrong)" + ) + else: + status = str(engine_result["status"]) + reason = engine_result.get("reason") + engine_results[engine.name] = { + "status": status, + "matched": matched, + "total": total, + "mismatched_cells": mismatches, + "reason": reason, + } + + results = { + "fixture": str(fixture), + "oracle": expected_data.get("oracle"), + "engines": engine_results, + } + render_calc_results(results, output_dir) + return results + + +def _compare_expected_values( + expected_cells: Mapping[str, Any], actual_values: Mapping[str, Any] +) -> tuple[int, list[dict[str, Any]]]: + matched = 0 + mismatches: list[dict[str, Any]] = [] + for reference, expected_cell in expected_cells.items(): + if not isinstance(expected_cell, Mapping) or "value" not in expected_cell: + raise ValueError(f"Expected cell {reference} has no value") + expected_value = expected_cell["value"] + actual_value = actual_values.get(reference) + if values_match(expected_value, actual_value): + matched += 1 + elif len(mismatches) < 10: + mismatches.append( + {"cell": reference, "expected": expected_value, "actual": actual_value} + ) + return matched, mismatches + + +def _engines() -> tuple[CalcEngine, ...]: + return ( + WolfXLCalcEngine(), + LibreOfficeCalcEngine(), + AsposeCellsFossCalcEngine(), + ZavoraCalcEngine(), + ) + + +def _load_expected(expected: dict[str, Any] | Path) -> dict[str, Any]: + if isinstance(expected, Path): + expected_path = ( + expected / "expected_values.json" if expected.is_dir() else expected + ) + loaded: dict[str, Any] = json.loads(expected_path.read_text()) + return loaded + return expected + + +def _repository_root() -> Path: + return Path(__file__).resolve().parents[3] diff --git a/src/excelbench/harness/external_oracles.py b/src/excelbench/harness/external_oracles.py index 54d9dd3..6f7d535 100644 --- a/src/excelbench/harness/external_oracles.py +++ b/src/excelbench/harness/external_oracles.py @@ -117,7 +117,9 @@ class ExternalOracleResult: notes: str | None = None -def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, ExternalOracleTool]: +def external_oracle_catalog( + repo_root: Path | None = None, +) -> dict[str, ExternalOracleTool]: """Return the planned external-oracle helper catalog. The commands are helper entrypoints, not raw runtime commands. They are @@ -133,7 +135,13 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External if repo_root is not None: libreoffice_command = ( sys.executable, - str(repo_root / "tools" / "external-oracles" / "libreoffice" / "libreoffice_oracle.py"), + str( + repo_root + / "tools" + / "external-oracles" + / "libreoffice" + / "libreoffice_oracle.py" + ), ) closedxml_command: tuple[str, ...] = ("excelbench-closedxml-oracle",) if repo_root is not None: @@ -141,7 +149,13 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External "dotnet", "run", "--project", - str(repo_root / "tools" / "external-oracles" / "closedxml" / "closedxml-oracle.csproj"), + str( + repo_root + / "tools" + / "external-oracles" + / "closedxml" + / "closedxml-oracle.csproj" + ), "--configuration", "Release", "--no-launch-profile", @@ -155,7 +169,9 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External "dotnet", "run", "--project", - str(repo_root / "tools" / "external-oracles" / "npoi" / "npoi-oracle.csproj"), + str( + repo_root / "tools" / "external-oracles" / "npoi" / "npoi-oracle.csproj" + ), "--configuration", "Release", "--no-launch-profile", @@ -169,7 +185,9 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External if repo_root is not None: exceljs_cwd = repo_root / "tools" / "external-oracles" / "exceljs" exceljs_command = ("node", str(exceljs_cwd / "exceljs-oracle.cjs")) - exceljs_required_paths = (exceljs_cwd / "node_modules" / "exceljs" / "package.json",) + exceljs_required_paths = ( + exceljs_cwd / "node_modules" / "exceljs" / "package.json", + ) apache_poi_command: tuple[str, ...] = ("excelbench-poi-oracle",) apache_poi_cwd = None apache_poi_required_paths: tuple[Path, ...] = () @@ -184,6 +202,14 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External apache_poi_cwd / "deps" / "lib" / "poi-ooxml-5.5.1.jar", ) + zavora_command: tuple[str, ...] = ("excelbench-zavora-oracle",) + zavora_cwd = None + zavora_required_paths: tuple[Path, ...] = () + if repo_root is not None: + zavora_cwd = repo_root / "tools" / "external-oracles" / "zavora" + zavora_command = ("cargo", "run", "--quiet") + zavora_required_paths = (zavora_cwd / "Cargo.toml",) + return { "excelize": ExternalOracleTool( name="excelize", @@ -243,14 +269,27 @@ def external_oracle_catalog(repo_root: Path | None = None) -> dict[str, External command=closedxml_command, language="dotnet", homepage="https://docs.closedxml.io/", - capabilities=frozenset({"read", "write", "pivots", "conditional_formatting"}), + capabilities=frozenset( + {"read", "write", "pivots", "conditional_formatting"} + ), ), "npoi": ExternalOracleTool( name="npoi", command=npoi_command, language="dotnet", homepage="https://github.com/nissl-lab/npoi", - capabilities=frozenset({"read", "write", "comments", "rich_text", "protection"}), + capabilities=frozenset( + {"read", "write", "comments", "rich_text", "protection"} + ), + ), + "zavora": ExternalOracleTool( + name="zavora", + command=zavora_command, + language="rust", + homepage="https://github.com/zavora-ai/zavora-xlsx", + capabilities=frozenset({"read", "write", "mutate", "calculate"}), + cwd=zavora_cwd, + required_paths=zavora_required_paths, ), } diff --git a/src/excelbench/harness/mutation.py b/src/excelbench/harness/mutation.py new file mode 100644 index 0000000..7f65826 --- /dev/null +++ b/src/excelbench/harness/mutation.py @@ -0,0 +1,364 @@ +"""Isolated mutation timing and OOXML preservation scoring.""" + +from __future__ import annotations + +import hashlib +import json +import os +import posixpath +import re +import shutil +import statistics +import subprocess +import sys +import time +import xml.etree.ElementTree as ET +from pathlib import Path, PurePosixPath +from typing import Any +from zipfile import ZipFile + +import openpyxl + +from excelbench.modifiable import ModifiableEngine, Mutation, modifiable_engines + +_WORKSHEET_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" +_RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships" +_CONTENT_TYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types" +_DRIVER = """ +import json +import sys +from pathlib import Path +from excelbench.modifiable import modifiable_engines + +name, template, output, mutations = sys.argv[1:] +engine = next(item for item in modifiable_engines() if item.name == name) +engine.mutate(Path(template), Path(output), json.loads(mutations)) +""" +_ELAPSED_RE = re.compile(r"^\s*(?P\d+(?:\.\d+)?)\s+real\b", re.MULTILINE) +_RSS_RE = re.compile(r"^\s*(?P\d+)\s+maximum resident set size\b", re.MULTILINE) +_ELEMENT_CHECKS = ( + "tableParts", + "sheetProtection", + "dataValidations", + "conditionalFormatting", + "pageSetup", + "headerFooter", + "sheetPr", + "pane", + "drawing", +) + + +def _sha256_file(path: Path) -> str: + """Return a SHA-256 digest for a complete file.""" + digest = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def _package_parts(path: Path) -> dict[str, bytes]: + """Read all file parts from an OOXML zip package.""" + with ZipFile(path) as archive: + return { + name: archive.read(name) + for name in archive.namelist() + if not name.endswith("/") + } + + +def _xml_has_element(xml: bytes, element: str) -> bool: + """Return whether a worksheet XML part contains the given main-namespace element.""" + try: + root = ET.fromstring(xml) + except ET.ParseError: + return False + return root.find(f".//{{{_WORKSHEET_NS}}}{element}") is not None + + +def _element_checklist( + original_parts: dict[str, bytes], output_parts: dict[str, bytes] +) -> list[dict[str, Any]]: + """Compare preservation-relevant worksheet elements part by part.""" + checks: list[dict[str, Any]] = [] + for part_name in sorted( + name + for name in original_parts + if name.startswith("xl/worksheets/") and name.endswith(".xml") + ): + original_xml = original_parts[part_name] + output_xml = output_parts.get(part_name, b"") + for element in _ELEMENT_CHECKS: + present_in_original = _xml_has_element(original_xml, element) + present_in_output = _xml_has_element(output_xml, element) + checks.append( + { + "part": part_name, + "element": element, + "present_in_original": present_in_original, + "present_in_output": present_in_output, + } + ) + return checks + + +def _relationship_target(rel_part: str, target: str) -> str: + """Resolve an internal relationship target to its package part name.""" + if target.startswith("/"): + return target.removeprefix("/") + rel_path = PurePosixPath(rel_part) + owner_directory = rel_path.parent.parent + return posixpath.normpath(posixpath.join(str(owner_directory), target)) + + +def _dangling_relationships(parts: dict[str, bytes]) -> list[str]: + """Return unresolved internal relationship targets declared under ``xl/``.""" + dangling: list[str] = [] + relationship_tag = f"{{{_RELATIONSHIPS_NS}}}Relationship" + for rel_part, xml in sorted(parts.items()): + if not rel_part.startswith("xl/") or not rel_part.endswith(".rels"): + continue + try: + root = ET.fromstring(xml) + except ET.ParseError: + dangling.append(f"{rel_part}: invalid relationship XML") + continue + for relationship in root.findall(relationship_tag): + if relationship.get("TargetMode") == "External": + continue + target = relationship.get("Target") + if not target: + dangling.append(f"{rel_part}: missing target") + continue + resolved = _relationship_target(rel_part, target) + if resolved.startswith("xl/") and resolved not in parts: + dangling.append(f"{rel_part}: {resolved}") + return dangling + + +def _missing_content_types(parts: dict[str, bytes]) -> list[str]: + """Return package parts lacking an OOXML content-type declaration.""" + content_types = parts.get("[Content_Types].xml") + if content_types is None: + return ["[Content_Types].xml"] + try: + root = ET.fromstring(content_types) + except ET.ParseError: + return ["[Content_Types].xml"] + default_tag = f"{{{_CONTENT_TYPES_NS}}}Default" + override_tag = f"{{{_CONTENT_TYPES_NS}}}Override" + defaults = {item.get("Extension") for item in root.findall(default_tag)} + overrides = { + item.get("PartName", "").removeprefix("/") + for item in root.findall(override_tag) + } + missing: list[str] = [] + for part_name in sorted(parts): + if part_name == "[Content_Types].xml": + continue + extension = part_name.rsplit(".", 1)[-1] if "." in part_name else "" + if part_name not in overrides and extension not in defaults: + missing.append(part_name) + return missing + + +def score_preservation(template: Path, output: Path) -> dict[str, Any]: + """Score a mutation output against its original OOXML package structure.""" + original_parts = _package_parts(template) + output_parts = _package_parts(output) + original_names = set(original_parts) + output_names = set(output_parts) + lost_parts = sorted(original_names - output_names) + added_parts = sorted(output_names - original_names) + + checklist = _element_checklist(original_parts, output_parts) + expected_checks = [entry for entry in checklist if entry["present_in_original"]] + retained_checks = [entry for entry in expected_checks if entry["present_in_output"]] + element_score = 30.0 + if expected_checks: + element_score *= len(retained_checks) / len(expected_checks) + + dangling_rels = _dangling_relationships(output_parts) + missing_content_types = _missing_content_types(output_parts) + integrity_issue_count = len(dangling_rels) + len(missing_content_types) + integrity_score = max(0.0, 20.0 - 5.0 * integrity_issue_count) + + custom_parts = sorted( + name for name in original_parts if name.startswith("customXml/") + ) + custom_xml_identical = all( + name in output_parts + and hashlib.sha256(original_parts[name]).digest() + == hashlib.sha256(output_parts[name]).digest() + for name in custom_parts + ) + custom_xml_score = 10.0 if custom_xml_identical else 0.0 + parts_score = max(0.0, 40.0 - 10.0 * len(lost_parts)) + preservation_score = round( + parts_score + element_score + integrity_score + custom_xml_score, 2 + ) + + return { + "preservation_score": preservation_score, + "details": { + "lost_parts": lost_parts, + "added_parts": added_parts, + "element_diffs": checklist, + "dangling_rels": dangling_rels, + "missing_content_types": missing_content_types, + "customXml_identical": custom_xml_identical, + }, + } + + +def _parse_time_output(stderr: str) -> tuple[float | None, float | None]: + """Extract macOS ``time -l`` elapsed seconds and RSS kilobytes.""" + elapsed_match = _ELAPSED_RE.search(stderr) + rss_match = _RSS_RE.search(stderr) + elapsed_seconds = float(elapsed_match.group("seconds")) if elapsed_match else None + rss_kb = float(rss_match.group("rss")) / 1024 if rss_match else None + return elapsed_seconds, rss_kb + + +def _run_subprocess_mutation( + engine: ModifiableEngine, + template: Path, + output: Path, + mutations: list[Mutation], +) -> tuple[float, float]: + """Run one isolated mutation and return elapsed milliseconds and RSS kilobytes.""" + command = [ + "/usr/bin/time", + "-l", + sys.executable, + "-c", + _DRIVER, + engine.name, + str(template), + str(output), + json.dumps(mutations, sort_keys=True), + ] + completed = subprocess.run(command, text=True, capture_output=True, check=False) + elapsed_seconds, peak_rss_kb = _parse_time_output(completed.stderr) + if completed.returncode != 0: + message = ( + completed.stderr.strip() + or completed.stdout.strip() + or "mutation driver failed" + ) + raise RuntimeError(message) + if elapsed_seconds is None or peak_rss_kb is None: + raise RuntimeError( + f"Unable to parse /usr/bin/time -l output: {completed.stderr.strip()}" + ) + return elapsed_seconds * 1000, peak_rss_kb + + +def _mutations_for_engine(manifest: dict[str, Any], engine_name: str) -> list[Mutation]: + """Materialize the fixture's engine-specific mutation values.""" + first = dict(manifest["mutation"]) + first["value"] = str(first["value"]).replace("", engine_name) + return [first, dict(manifest["second_mutation"])] + + +def _mutations_landed(output: Path, mutations: list[Mutation]) -> bool: + """Verify the requested values after a mutation output is written.""" + try: + workbook = openpyxl.load_workbook(output, data_only=False) + except Exception: + return False + try: + return all( + workbook[str(mutation["sheet"])][str(mutation["cell"])].value + == mutation["value"] + for mutation in mutations + ) + finally: + workbook.close() + + +def run_mutation_suite( + template: Path, output_dir: Path, repeats: int = 3 +) -> dict[str, Any]: + """Benchmark isolated surgical mutations and score package preservation.""" + if repeats < 1: + raise ValueError("repeats must be at least 1") + template = Path(template) + output_dir = Path(output_dir) + if not template.is_file(): + raise FileNotFoundError(template) + manifest_path = template.with_name("manifest.json") + manifest = json.loads(manifest_path.read_text(encoding="utf-8")) + output_dir.mkdir(parents=True, exist_ok=True) + + engine_results: dict[str, dict[str, Any]] = {} + for engine in modifiable_engines(): + if not engine.available(): + engine_results[engine.name] = { + "available": False, + "status": "unavailable", + "wall_ms_median": None, + "peak_rss_kb_median": None, + "preservation_score": None, + "details": {"reason": "engine unavailable"}, + } + continue + + engine_dir = output_dir / engine.name + engine_dir.mkdir(parents=True, exist_ok=True) + mutations = _mutations_for_engine(manifest, engine.name) + wall_times: list[float] = [] + peak_rss_values: list[float] = [] + final_output: Path | None = None + try: + for repeat_index in range(repeats): + input_path = engine_dir / f"repeat-{repeat_index + 1}-input.xlsx" + output_path = engine_dir / f"repeat-{repeat_index + 1}-output.xlsx" + shutil.copyfile(template, input_path) + output_path.unlink(missing_ok=True) + wall_ms, peak_rss_kb = _run_subprocess_mutation( + engine, input_path, output_path, mutations + ) + wall_times.append(wall_ms) + peak_rss_values.append(peak_rss_kb) + final_output = output_path + if final_output is None: + raise RuntimeError("mutation suite did not produce an output") + scored = score_preservation(template, final_output) + mutations_landed = _mutations_landed(final_output, mutations) + details = dict(scored["details"]) + details["mutations_landed"] = mutations_landed + if not mutations_landed: + details["integrity_failure"] = ( + "mutated cell values did not match requested values" + ) + engine_results[engine.name] = { + "available": True, + "status": "passed" if mutations_landed else "integrity-failed", + "wall_ms_median": round(statistics.median(wall_times), 3), + "peak_rss_kb_median": round(statistics.median(peak_rss_values), 3), + "preservation_score": scored["preservation_score"] + if mutations_landed + else 0.0, + "details": details, + } + except Exception as error: + engine_results[engine.name] = { + "available": True, + "status": "failed", + "wall_ms_median": None, + "peak_rss_kb_median": None, + "preservation_score": None, + "details": {"error": f"{type(error).__name__}: {error}"}, + } + + return { + "metadata": { + "template_sha256": _sha256_file(template), + "repeats": repeats, + "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + "platform": os.uname().sysname, + }, + "engines": engine_results, + } diff --git a/src/excelbench/harness/runner.py b/src/excelbench/harness/runner.py index 773a4de..8d02dbc 100644 --- a/src/excelbench/harness/runner.py +++ b/src/excelbench/harness/runner.py @@ -194,7 +194,9 @@ def run_benchmark( "(fixtures/excel/tier2/15_pivot_tables.xlsx)." ) all_scores.append(score) - print(f" {adapter.name}: read={score.read_score}, write={score.write_score}") + print( + f" {adapter.name}: read={score.read_score}, write={score.write_score}" + ) return BenchmarkResults( metadata=metadata, @@ -292,7 +294,12 @@ def _annotate_known_limitations(score: FeatureScore) -> FeatureScore: if limitation is None: return score side, note = limitation - if side == "read" and score.read_score is not None and score.read_score < 3 and not score.notes: + if ( + side == "read" + and score.read_score is not None + and score.read_score < 3 + and not score.notes + ): score.notes = note if ( side == "write" @@ -493,6 +500,12 @@ def test_read_case( actual = read_comment_actual(adapter, workbook, sheet, expected) elif feature == "freeze_panes": actual = read_freeze_panes_actual(adapter, workbook, sheet, expected) + elif feature == "sheet_protection": + actual = read_sheet_protection_actual(adapter, workbook, sheet) + elif feature == "page_setup": + actual = read_page_setup_actual(adapter, workbook, sheet) + elif feature == "chart_anchor": + actual = read_chart_anchor_actual(adapter, workbook, sheet) else: actual = {"error": f"Unknown feature: {feature}"} @@ -502,6 +515,10 @@ def test_read_case( cmp_expected = expected if feature == "conditional_formatting": cmp_expected = _strip_cf_priority(expected) + if feature == "sheet_protection": + cmp_expected = _strip_protection_password(cmp_expected) + if feature == "chart_anchor": + cmp_expected = _strip_chart_write_refs(cmp_expected) passed = compare_results(cmp_expected, actual) return TestResult( @@ -770,7 +787,9 @@ def read_merged_cells_actual( if match: start_cell, end_cell = _split_range(match) if expected.get("top_left_value") is not None: - result["top_left_value"] = _read_cell_scalar(adapter, workbook, sheet, start_cell) + result["top_left_value"] = _read_cell_scalar( + adapter, workbook, sheet, start_cell + ) if expected.get("non_top_left_nonempty") is not None: count = 0 for cell in _cells_in_range(start_cell, end_cell): @@ -782,12 +801,16 @@ def read_merged_cells_actual( result["non_top_left_nonempty"] = count if expected.get("top_left_bg_color") is not None: fmt = adapter.read_cell_format(workbook, sheet, start_cell) - result["top_left_bg_color"] = fmt.bg_color.upper() if fmt.bg_color else None + result["top_left_bg_color"] = ( + fmt.bg_color.upper() if fmt.bg_color else None + ) if expected.get("non_top_left_bg_color") is not None: other = _first_non_top_left_cell(start_cell, end_cell) if other: fmt = adapter.read_cell_format(workbook, sheet, other) - result["non_top_left_bg_color"] = fmt.bg_color.upper() if fmt.bg_color else None + result["non_top_left_bg_color"] = ( + fmt.bg_color.upper() if fmt.bg_color else None + ) return result @@ -803,6 +826,40 @@ def _strip_cf_priority(expected: JSONDict) -> JSONDict: return out +def _strip_protection_password(expected: JSONDict) -> JSONDict: + """Return a copy of *expected* without the write-only protection password. + + The manifest carries the plaintext password so the write lane can apply + it; readers can only observe ``password_hash_present``. + """ + wrapped = "protection" in expected + protection = expected.get("protection", expected) + if not isinstance(protection, dict) or "password" not in protection: + return expected + stripped = {k: v for k, v in protection.items() if k != "password"} + if wrapped: + return {**expected, "protection": stripped} + return stripped + + +def _strip_chart_write_refs(expected: JSONDict) -> JSONDict: + """Return a copy of *expected* without write-only chart series refs. + + ``data_ref``/``categories_ref`` feed ``add_chart_with_anchor`` in the + write lane; ``read_chart_anchors`` only reports type/anchor/cells. + """ + charts = expected.get("charts") + if not isinstance(charts, list): + return expected + stripped = [ + {k: v for k, v in chart.items() if k not in ("data_ref", "categories_ref")} + if isinstance(chart, dict) + else chart + for chart in charts + ] + return {**expected, "charts": stripped} + + def read_conditional_format_actual( adapter: ExcelAdapter, workbook: Any, @@ -880,7 +937,11 @@ def read_image_actual( normalized = dict(match) expected_path = expected_rule.get("path") actual_path = normalized.get("path") - if expected_path and isinstance(actual_path, str) and actual_path.startswith("/xl/media/"): + if ( + expected_path + and isinstance(actual_path, str) + and actual_path.startswith("/xl/media/") + ): normalized["path"] = expected_path return {"image": _project_rule(normalized, expected_rule)} @@ -942,6 +1003,36 @@ def read_freeze_panes_actual( return {"freeze": _project_rule(settings, expected_rule)} +def read_sheet_protection_actual( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, +) -> JSONDict: + """Read sheet protection settings and return as comparable dict.""" + settings = adapter.read_sheet_protection(workbook, sheet) + return {"protection": settings} + + +def read_page_setup_actual( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, +) -> JSONDict: + """Read page setup settings and return as comparable dict.""" + settings = adapter.read_page_setup(workbook, sheet) + return {"page_setup": settings} + + +def read_chart_anchor_actual( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, +) -> JSONDict: + """Read chart anchors and return as comparable dict.""" + charts = adapter.read_chart_anchors(workbook, sheet) + return {"charts": charts} + + def _normalize_named_range_refers_to(value: Any) -> str: if value is None: return "" @@ -983,7 +1074,9 @@ def read_named_ranges_actual( expected_scope = expected.get("scope") expected_ref = expected.get("refers_to") expected_ref_norm = ( - _normalize_named_range_refers_to(expected_ref) if isinstance(expected_ref, str) else None + _normalize_named_range_refers_to(expected_ref) + if isinstance(expected_ref, str) + else None ) for nr in all_names: @@ -1128,9 +1221,13 @@ def test_write( adapter, workbook, target_sheet, target_cell, tc.expected ) elif test_file.feature == "formulas": - _write_formula_case(adapter, workbook, target_sheet, target_cell, tc.expected) + _write_formula_case( + adapter, workbook, target_sheet, target_cell, tc.expected + ) elif test_file.feature == "text_formatting": - _write_text_format_case(adapter, workbook, target_sheet, target_cell, tc) + _write_text_format_case( + adapter, workbook, target_sheet, target_cell, tc + ) elif test_file.feature == "background_colors": _write_background_color_case( adapter, @@ -1164,7 +1261,9 @@ def test_write( tc.expected, ) elif test_file.feature == "dimensions": - _write_dimensions_case(adapter, workbook, target_sheet, target_cell, tc) + _write_dimensions_case( + adapter, workbook, target_sheet, target_cell, tc + ) elif test_file.feature == "multiple_sheets": _write_multi_sheet_case( adapter, @@ -1174,15 +1273,23 @@ def test_write( tc.expected, ) elif test_file.feature == "merged_cells": - _write_merged_cells_case(adapter, workbook, target_sheet, tc.expected) + _write_merged_cells_case( + adapter, workbook, target_sheet, tc.expected + ) elif test_file.feature == "conditional_formatting": - _write_conditional_format_case(adapter, workbook, target_sheet, tc.expected) + _write_conditional_format_case( + adapter, workbook, target_sheet, tc.expected + ) elif test_file.feature == "data_validation": - _write_data_validation_case(adapter, workbook, target_sheet, tc.expected) + _write_data_validation_case( + adapter, workbook, target_sheet, tc.expected + ) elif test_file.feature == "hyperlinks": _write_hyperlink_case(adapter, workbook, target_sheet, tc.expected) elif test_file.feature == "named_ranges": - _write_named_range_case(adapter, workbook, target_sheet, tc.expected) + _write_named_range_case( + adapter, workbook, target_sheet, tc.expected + ) elif test_file.feature == "tables": _write_table_case(adapter, workbook, target_sheet, tc.expected) elif test_file.feature == "images": @@ -1192,7 +1299,19 @@ def test_write( elif test_file.feature == "comments": _write_comment_case(adapter, workbook, target_sheet, tc.expected) elif test_file.feature == "freeze_panes": - _write_freeze_panes_case(adapter, workbook, target_sheet, tc.expected) + _write_freeze_panes_case( + adapter, workbook, target_sheet, tc.expected + ) + elif test_file.feature == "sheet_protection": + _write_sheet_protection_case( + adapter, workbook, target_sheet, tc.expected + ) + elif test_file.feature == "page_setup": + _write_page_setup_case(adapter, workbook, target_sheet, tc.expected) + elif test_file.feature == "chart_anchor": + _write_chart_anchor_case( + adapter, workbook, target_sheet, tc.expected + ) adapter.save_workbook(workbook, output_path) except Exception as e: @@ -1380,7 +1499,11 @@ def get_write_verifier_for_feature(feature: str) -> ExcelAdapter: return get_write_verifier() if platform.system() == "Darwin": return OpenpyxlAdapter() - if feature in complex_features and _excel_available() and ExcelOracleAdapter is not None: + if ( + feature in complex_features + and _excel_available() + and ExcelOracleAdapter is not None + ): return ExcelOracleAdapter() return OpenpyxlAdapter() @@ -1418,7 +1541,9 @@ def _collect_sheet_names(test_file: TestFile) -> list[str]: explicit = True break if test_file.feature == "formulas": - sheet_names.extend(_extract_formula_sheet_names(tc.expected.get("formula", ""))) + sheet_names.extend( + _extract_formula_sheet_names(tc.expected.get("formula", "")) + ) if test_file.feature == "conditional_formatting": rule = tc.expected.get("cf_rule", {}) formula = rule.get("formula") @@ -1520,28 +1645,34 @@ def _find_by_key(items: list[JSONDict], key: str, value: Any) -> JSONDict | None def _find_rule(rules: list[JSONDict], expected: JSONDict) -> JSONDict | None: for rule in rules: - if expected.get("range") and _normalize_range(rule.get("range", "")) != _normalize_range( - expected.get("range", "") - ): + if expected.get("range") and _normalize_range( + rule.get("range", "") + ) != _normalize_range(expected.get("range", "")): continue - if expected.get("rule_type") and rule.get("rule_type") != expected.get("rule_type"): + if expected.get("rule_type") and rule.get("rule_type") != expected.get( + "rule_type" + ): continue if expected.get("formula") and rule.get("formula"): - if _normalize_formula(expected["formula"]) != _normalize_formula(rule["formula"]): + if _normalize_formula(expected["formula"]) != _normalize_formula( + rule["formula"] + ): continue return rule return None -def _find_validation(validations: list[JSONDict], expected: JSONDict) -> JSONDict | None: +def _find_validation( + validations: list[JSONDict], expected: JSONDict +) -> JSONDict | None: for validation in validations: if expected.get("range") and _normalize_range( validation.get("range", "") ) != _normalize_range(expected.get("range", "")): continue - if expected.get("validation_type") and validation.get("validation_type") != expected.get( + if expected.get("validation_type") and validation.get( "validation_type" - ): + ) != expected.get("validation_type"): continue if expected.get("formula1"): if _normalize_formula(validation.get("formula1")) != _normalize_formula( @@ -1587,10 +1718,14 @@ def _quote_match(m: re.Match[str]) -> str: return f"='{name}'!{cell_ref}" # Match =SheetName!CellRef where SheetName is not already quoted - return re.sub(r"=([A-Za-z0-9_][A-Za-z0-9_ ]*)!(\$?[A-Z]+\$?[0-9]+)", _quote_match, formula) + return re.sub( + r"=([A-Za-z0-9_][A-Za-z0-9_ ]*)!(\$?[A-Z]+\$?[0-9]+)", _quote_match, formula + ) -def _read_cell_scalar(adapter: ExcelAdapter, workbook: Any, sheet: str, cell: str) -> Any: +def _read_cell_scalar( + adapter: ExcelAdapter, workbook: Any, sheet: str, cell: str +) -> Any: cell_value = adapter.read_cell_value(workbook, sheet, cell) if cell_value.type == CellType.BLANK: return None @@ -1724,8 +1859,12 @@ def _write_cell_value_case( adapter.write_cell_value(workbook, sheet, cell, cell_value) if cell_value.type in (CellType.DATE, CellType.DATETIME): - number_format = "yyyy-mm-dd" if cell_value.type == CellType.DATE else "yyyy-mm-dd hh:mm:ss" - adapter.write_cell_format(workbook, sheet, cell, CellFormat(number_format=number_format)) + number_format = ( + "yyyy-mm-dd" if cell_value.type == CellType.DATE else "yyyy-mm-dd hh:mm:ss" + ) + adapter.write_cell_format( + workbook, sheet, cell, CellFormat(number_format=number_format) + ) def _write_formula_case( @@ -1753,7 +1892,9 @@ def _write_text_format_case( cell, CellValue(type=CellType.STRING, value=test_case.label), ) - adapter.write_cell_format(workbook, sheet, cell, _cell_format_from_expected(test_case.expected)) + adapter.write_cell_format( + workbook, sheet, cell, _cell_format_from_expected(test_case.expected) + ) def _write_background_color_case( @@ -1763,8 +1904,12 @@ def _write_background_color_case( cell: str, expected: JSONDict, ) -> None: - adapter.write_cell_value(workbook, sheet, cell, CellValue(type=CellType.STRING, value="Color")) - adapter.write_cell_format(workbook, sheet, cell, _cell_format_from_expected(expected)) + adapter.write_cell_value( + workbook, sheet, cell, CellValue(type=CellType.STRING, value="Color") + ) + adapter.write_cell_format( + workbook, sheet, cell, _cell_format_from_expected(expected) + ) def _write_number_format_case( @@ -1784,8 +1929,12 @@ def _write_number_format_case( # passes where libraries ignore write_cell_format() but a default date # number format is auto-assigned for native date objects. value = 45326.0 # 2024-02-04 in Excel's 1900 date system. - adapter.write_cell_value(workbook, sheet, cell, CellValue(type=value_type, value=value)) - adapter.write_cell_format(workbook, sheet, cell, _cell_format_from_expected(expected)) + adapter.write_cell_value( + workbook, sheet, cell, CellValue(type=value_type, value=value) + ) + adapter.write_cell_format( + workbook, sheet, cell, _cell_format_from_expected(expected) + ) def _write_alignment_case( @@ -1795,8 +1944,12 @@ def _write_alignment_case( cell: str, expected: JSONDict, ) -> None: - adapter.write_cell_value(workbook, sheet, cell, CellValue(type=CellType.STRING, value="Align")) - adapter.write_cell_format(workbook, sheet, cell, _cell_format_from_expected(expected)) + adapter.write_cell_value( + workbook, sheet, cell, CellValue(type=CellType.STRING, value="Align") + ) + adapter.write_cell_format( + workbook, sheet, cell, _cell_format_from_expected(expected) + ) def _write_border_case( @@ -1806,7 +1959,9 @@ def _write_border_case( cell: str, expected: JSONDict, ) -> None: - adapter.write_cell_value(workbook, sheet, cell, CellValue(type=CellType.STRING, value="Border")) + adapter.write_cell_value( + workbook, sheet, cell, CellValue(type=CellType.STRING, value="Border") + ) adapter.write_cell_border(workbook, sheet, cell, _border_from_expected(expected)) @@ -1818,10 +1973,14 @@ def _write_dimensions_case( test_case: TestCase, ) -> None: if "row_height" in test_case.expected: - adapter.set_row_height(workbook, sheet, test_case.row, test_case.expected["row_height"]) + adapter.set_row_height( + workbook, sheet, test_case.row, test_case.expected["row_height"] + ) if "column_width" in test_case.expected: column = _extract_column(cell) - adapter.set_column_width(workbook, sheet, column, test_case.expected["column_width"]) + adapter.set_column_width( + workbook, sheet, column, test_case.expected["column_width"] + ) def _write_multi_sheet_case( @@ -1903,7 +2062,9 @@ def _write_named_range_case( if "value" in expected: refers_to = expected.get("refers_to") if isinstance(refers_to, str): - loc = _parse_named_range_single_cell(_normalize_named_range_refers_to(refers_to)) + loc = _parse_named_range_single_cell( + _normalize_named_range_refers_to(refers_to) + ) if loc is not None: ref_sheet, ref_cell = loc adapter.write_cell_value( @@ -1986,6 +2147,36 @@ def _write_freeze_panes_case( adapter.set_freeze_panes(workbook, sheet, expected) +def _write_sheet_protection_case( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, + expected: JSONDict, +) -> None: + settings = expected.get("protection", expected) + adapter.set_sheet_protection(workbook, sheet, settings) + + +def _write_page_setup_case( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, + expected: JSONDict, +) -> None: + settings = expected.get("page_setup", expected) + adapter.set_page_setup(workbook, sheet, settings) + + +def _write_chart_anchor_case( + adapter: ExcelAdapter, + workbook: Any, + sheet: str, + expected: JSONDict, +) -> None: + for chart in expected.get("charts", []): + adapter.add_chart_with_anchor(workbook, sheet, chart) + + def calculate_score(results: list[TestResult]) -> int: """Calculate fidelity score from test results. diff --git a/src/excelbench/modifiable.py b/src/excelbench/modifiable.py new file mode 100644 index 0000000..da78967 --- /dev/null +++ b/src/excelbench/modifiable.py @@ -0,0 +1,204 @@ +"""Workbook engines used by the surgical mutation benchmark.""" + +from __future__ import annotations + +import shutil +from pathlib import Path +from typing import Any, Protocol + +from excelbench.harness.external_oracles import ( + ExternalOracleRequest, + external_oracle_catalog, + run_external_oracle, +) + +_openpyxl: Any = None +_wolfxl: Any = None +_aspose_cells_foss: Any = None + +try: + import openpyxl + + _openpyxl = openpyxl +except ImportError: # pragma: no cover - optional dependency guard + pass + +try: + import wolfxl + + _wolfxl = wolfxl +except ImportError: # pragma: no cover - optional dependency guard + pass + +try: + import aspose.cells_foss + + _aspose_cells_foss = aspose.cells_foss +except ImportError: # pragma: no cover - optional dependency guard + pass + +Mutation = dict[str, Any] +_REPO_ROOT = Path(__file__).resolve().parents[2] + + +class ModifiableEngine(Protocol): + """Protocol implemented by engines that can modify an existing workbook.""" + + name: str + + def available(self) -> bool: + """Return whether this engine is installed and usable.""" + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Apply all mutations to a template workbook and save the output.""" + + +def _mutation_target(mutation: Mutation) -> tuple[str, str, Any]: + """Validate and unpack one mutation payload.""" + try: + sheet = mutation["sheet"] + cell = mutation["cell"] + value = mutation["value"] + except KeyError as error: + raise ValueError( + f"Mutation is missing required key: {error.args[0]}" + ) from error + if not isinstance(sheet, str) or not sheet: + raise ValueError("Mutation sheet must be a non-empty string") + if not isinstance(cell, str) or not cell: + raise ValueError("Mutation cell must be a non-empty string") + return sheet, cell, value + + +class OpenpyxlEngine: + """In-place workbook mutation through OpenPyXL.""" + + name = "openpyxl" + + def available(self) -> bool: + """Return whether OpenPyXL can be imported.""" + return _openpyxl is not None + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Apply mutations with OpenPyXL and save a new workbook package.""" + if _openpyxl is None: + raise RuntimeError("openpyxl is not installed") + output.parent.mkdir(parents=True, exist_ok=True) + workbook = _openpyxl.load_workbook(template) + try: + for mutation in mutations: + sheet, cell, value = _mutation_target(mutation) + workbook[sheet][cell] = value + workbook.save(output) + finally: + workbook.close() + + +class WolfxlEngine: + """In-place workbook mutation through WolfXL modify mode.""" + + name = "wolfxl" + + def available(self) -> bool: + """Return whether WolfXL can be imported.""" + return _wolfxl is not None + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Apply mutations with WolfXL's public modify-mode API.""" + if _wolfxl is None: + raise RuntimeError("wolfxl is not installed") + output.parent.mkdir(parents=True, exist_ok=True) + workbook = _wolfxl.load_workbook(template, modify=True) + for mutation in mutations: + sheet, cell, value = _mutation_target(mutation) + workbook[sheet][cell].value = value + workbook.save(output) + + +class AsposeFossEngine: + """In-place workbook mutation through aspose-cells-foss.""" + + name = "aspose-cells-foss" + + def available(self) -> bool: + """Return whether aspose-cells-foss can be imported.""" + return _aspose_cells_foss is not None + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Apply mutations with aspose-cells-foss and save a new workbook package.""" + if _aspose_cells_foss is None: + raise RuntimeError("aspose-cells-foss is not installed") + output.parent.mkdir(parents=True, exist_ok=True) + workbook = _aspose_cells_foss.Workbook(str(template)) + for mutation in mutations: + sheet, cell, value = _mutation_target(mutation) + worksheet = next( + ( + candidate + for candidate in workbook.worksheets + if candidate.name == sheet + ), + None, + ) + if worksheet is None: + raise KeyError(f"Worksheet not found: {sheet}") + worksheet.cells.get_cell_by_name(cell).value = value + workbook.save(str(output)) + + +class ZavoraEngine: + """In-place workbook mutation through the optional Zavora oracle helper.""" + + name = "zavora-xlsx" + + def available(self) -> bool: + """Return whether the Zavora helper command and source are available.""" + return external_oracle_catalog(_REPO_ROOT)["zavora"].is_available() + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Apply mutations through chained external-oracle requests.""" + tool = external_oracle_catalog(_REPO_ROOT)["zavora"] + if not tool.is_available(): + raise RuntimeError("zavora external oracle is unavailable") + output.parent.mkdir(parents=True, exist_ok=True) + if not mutations: + shutil.copyfile(template, output) + return + + intermediate_paths: list[Path] = [] + input_path = template.resolve() + try: + for index, mutation in enumerate(mutations): + sheet, cell, value = _mutation_target(mutation) + is_last = index == len(mutations) - 1 + next_path = output.resolve() + if not is_last: + next_path = output.with_name( + f".{output.stem}.mutation-{index}{output.suffix}" + ).resolve() + intermediate_paths.append(next_path) + request = ExternalOracleRequest( + fixture_id="mutation-template", + operation="mutate", + payload={"sheet": sheet, "cell": cell, "value": value}, + input_path=input_path, + output_path=next_path, + ) + result = run_external_oracle(tool, request) + if not result.passed: + detail = ( + result.notes + or result.stderr + or result.stdout + or "unknown oracle failure" + ) + raise RuntimeError(f"zavora mutation failed: {detail.strip()}") + input_path = next_path + finally: + for intermediate_path in intermediate_paths: + intermediate_path.unlink(missing_ok=True) + + +def modifiable_engines() -> list[ModifiableEngine]: + """Return the fixed engine registry used by the mutation suite.""" + return [OpenpyxlEngine(), WolfxlEngine(), AsposeFossEngine(), ZavoraEngine()] diff --git a/src/excelbench/results/calc_renderer.py b/src/excelbench/results/calc_renderer.py new file mode 100644 index 0000000..5e55b88 --- /dev/null +++ b/src/excelbench/results/calc_renderer.py @@ -0,0 +1,62 @@ +"""Render formula recalculation comparison results.""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + + +def render_calc_results(results: dict[str, Any], output_dir: Path) -> None: + """Write calculation results as JSON and a concise Markdown report.""" + output_dir.mkdir(parents=True, exist_ok=True) + (output_dir / "results.json").write_text( + json.dumps(results, indent=2, sort_keys=True) + "\n" + ) + (output_dir / "README.md").write_text(_render_markdown(results)) + + +def _render_markdown(results: dict[str, Any]) -> str: + engines = results.get("engines", {}) + lines = [ + "# ExcelBench Formula Recalculation Results", + "", + f"Oracle: {results.get('oracle') or 'unknown'}", + "", + "Formula values are compared with absolute tolerance 1e-6 or relative tolerance 1e-9 " + "for numbers; strings and booleans compare exactly.", + "", + "| Engine | Status | Matched/total | First mismatches |", + "| --- | --- | --- | --- |", + ] + if not isinstance(engines, dict): + engines = {} + for name, result in engines.items(): + if not isinstance(result, dict): + continue + mismatches = result.get("mismatched_cells", []) + mismatch_text = _mismatch_text(mismatches) + lines.append( + "| " + f"{name} | {result.get('status', 'unknown')} | " + f"{result.get('matched', 0)}/{result.get('total', 0)} | {mismatch_text} |" + ) + reason = result.get("reason") + if reason: + lines.extend(["", f"{name}: {reason}"]) + lines.append("") + return "\n".join(lines) + + +def _mismatch_text(mismatches: Any) -> str: + if not isinstance(mismatches, list) or not mismatches: + return "—" + rendered: list[str] = [] + for mismatch in mismatches[:10]: + if not isinstance(mismatch, dict): + continue + rendered.append( + f"{mismatch.get('cell')}: expected {mismatch.get('expected')!r}, " + f"actual {mismatch.get('actual')!r}" + ) + return "
".join(rendered).replace("|", "\\|") or "—" diff --git a/src/excelbench/results/mutation_renderer.py b/src/excelbench/results/mutation_renderer.py new file mode 100644 index 0000000..9c3c8ea --- /dev/null +++ b/src/excelbench/results/mutation_renderer.py @@ -0,0 +1,81 @@ +"""Rendering for surgical workbook mutation benchmark results.""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + + +def _format_number(value: object, suffix: str = "") -> str: + """Format an optional benchmark number for a Markdown cell.""" + if isinstance(value, int | float): + return f"{value:.3f}{suffix}" + return "—" + + +def _verdict(result: dict[str, Any]) -> str: + """Return a concise status label for an engine result.""" + status = result.get("status") + if status == "unavailable": + return "Unavailable" + if status == "failed": + return "Failed" + if status == "integrity-failed": + return "Mutation integrity failed" + if result.get("preservation_score") == 100: + return "Preserved" + return "Loss detected" + + +def render_mutation_report(results: dict[str, Any], output_dir: Path) -> None: + """Write ``results.json`` and a compact Markdown comparison report.""" + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + (output_dir / "results.json").write_text( + json.dumps(results, indent=2, sort_keys=True) + "\n", encoding="utf-8" + ) + + metadata = results.get("metadata", {}) + engine_results = results.get("engines", {}) + lines = [ + "# ExcelBench Mutation Results", + "", + f"*Generated: {metadata.get('timestamp', 'unknown')}*", + f"*Template SHA-256: {metadata.get('template_sha256', 'unknown')}*", + f"*Repeats: {metadata.get('repeats', 'unknown')}*", + "", + "## Comparison", + "", + "| Engine | Wall ms | Peak RSS KB | Preservation score | Lost parts | Verdict |", + "|--------|---------|-------------|--------------------|------------|---------|", + ] + for engine_name in sorted(engine_results): + result = engine_results[engine_name] + details = result.get("details", {}) + lost_parts = details.get("lost_parts", []) + lost_count = len(lost_parts) if isinstance(lost_parts, list) else "—" + score = result.get("preservation_score") + score_text = _format_number(score) if isinstance(score, int | float) else "—" + lines.append( + f"| {engine_name} | {_format_number(result.get('wall_ms_median'))} | " + f"{_format_number(result.get('peak_rss_kb_median'))} | {score_text} | " + f"{lost_count} | {_verdict(result)} |" + ) + lines.extend( + [ + "", + "## Notes", + "", + ( + "Wall time and peak RSS are measured in isolated subprocesses " + "with macOS `/usr/bin/time -l`." + ), + ( + "Preservation compares each output package against the original template. " + "It does not measure formula recalculation or rendering." + ), + "", + ] + ) + (output_dir / "README.md").write_text("\n".join(lines), encoding="utf-8") diff --git a/tests/test_aspose_cells_foss_adapter.py b/tests/test_aspose_cells_foss_adapter.py new file mode 100644 index 0000000..c2a1935 --- /dev/null +++ b/tests/test_aspose_cells_foss_adapter.py @@ -0,0 +1,129 @@ +"""Tests for the aspose-cells-foss adapter using its installed implementation.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +pytest.importorskip("aspose.cells_foss", reason="optional 'aspose' extra not installed") + +from excelbench.harness.adapters.aspose_cells_foss_adapter import ( + AsposeCellsFossAdapter, # noqa: E402 +) +from excelbench.harness.adapters.base import UnsupportedAdapterOperationError # noqa: E402 +from excelbench.models import ( # noqa: E402 + BorderEdge, + BorderInfo, + BorderStyle, + CellFormat, + CellType, + CellValue, +) + + +@pytest.fixture +def adapter() -> AsposeCellsFossAdapter: + return AsposeCellsFossAdapter() + + +def test_values_formats_and_dimensions_round_trip( + adapter: AsposeCellsFossAdapter, tmp_path: Path +) -> None: + """Values, formula text, formatting, borders, and dimensions survive an XLSX round trip.""" + path = tmp_path / "aspose-cells-foss.xlsx" + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "Data") + adapter.write_cell_value( + workbook, "Data", "A1", CellValue(type=CellType.STRING, value="hello") + ) + adapter.write_cell_value( + workbook, "Data", "B1", CellValue(type=CellType.NUMBER, value=42.5) + ) + adapter.write_cell_value( + workbook, + "Data", + "C1", + CellValue(type=CellType.FORMULA, value=None, formula="=B1*2"), + ) + adapter.write_cell_format( + workbook, + "Data", + "A1", + CellFormat( + bold=True, + italic=True, + underline="single", + strikethrough=True, + font_name="Arial", + font_size=16, + font_color="#FF0000", + bg_color="#FFFF00", + number_format="0.00", + h_align="center", + v_align="top", + wrap=True, + rotation=45, + indent=2, + ), + ) + adapter.write_cell_border( + workbook, + "Data", + "A1", + BorderInfo( + top=BorderEdge(style=BorderStyle.THIN, color="#FF0000"), + bottom=BorderEdge(style=BorderStyle.DOUBLE, color="#00FF00"), + ), + ) + adapter.set_row_height(workbook, "Data", 1, 30) + adapter.set_column_width(workbook, "Data", "A", 20) + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + assert adapter.get_sheet_names(reopened) == ["Data"] + assert adapter.read_cell_value(reopened, "Data", "A1") == CellValue( + type=CellType.STRING, value="hello" + ) + assert adapter.read_cell_value(reopened, "Data", "B1") == CellValue( + type=CellType.NUMBER, value=42.5 + ) + formula = adapter.read_cell_value(reopened, "Data", "C1") + assert formula.type == CellType.FORMULA + assert formula.formula == "=B1*2" + cell_format = adapter.read_cell_format(reopened, "Data", "A1") + assert cell_format.bold is True + assert cell_format.italic is True + assert cell_format.underline == "single" + assert cell_format.strikethrough is True + assert cell_format.font_name == "Arial" + assert cell_format.font_size == 16 + assert cell_format.font_color == "#FF0000" + assert cell_format.bg_color == "#FFFF00" + assert cell_format.number_format == "0.00" + assert cell_format.h_align == "center" + assert cell_format.v_align == "top" + assert cell_format.wrap is True + assert cell_format.rotation == 45 + assert cell_format.indent == 2 + border = adapter.read_cell_border(reopened, "Data", "A1") + assert border.top == BorderEdge(style=BorderStyle.THIN, color="#FF0000") + assert border.bottom == BorderEdge(style=BorderStyle.DOUBLE, color="#00FF00") + assert adapter.read_row_height(reopened, "Data", 1) == 30 + assert adapter.read_column_width(reopened, "Data", "A") == 20 + adapter.close_workbook(reopened) + + +def test_pivot_operations_raise_structured_unsupported_error( + adapter: AsposeCellsFossAdapter, +) -> None: + """The adapter reports its unsupported pivot capability without a silent no-op.""" + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "Data") + + with pytest.raises(UnsupportedAdapterOperationError) as error: + adapter.add_pivot_table(workbook, "Data", {}) + + assert error.value.adapter == "aspose-cells-foss" + assert error.value.operation == "add_pivot_table" + assert "no pivot-table API" in error.value.reason diff --git a/tests/test_calc_suite.py b/tests/test_calc_suite.py new file mode 100644 index 0000000..163d1b6 --- /dev/null +++ b/tests/test_calc_suite.py @@ -0,0 +1,106 @@ +"""Tests for the Formula Recalculation benchmark tier.""" + +from __future__ import annotations + +import json +from collections.abc import Callable +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path +from types import ModuleType +from typing import Any, cast + +import pytest + +from excelbench.harness.calc import ( + SOFFICE_PATH, + AsposeCellsFossCalcEngine, + LibreOfficeCalcEngine, + WolfXLCalcEngine, + formula_cells, + values_match, +) + +requires_libreoffice = pytest.mark.skipif( + not SOFFICE_PATH.is_file(), reason="LibreOffice binary not available" +) + +FIXTURE = Path("fixtures/calc/financial_model.xlsx") +EXPECTED = Path("fixtures/calc/expected_values.json") + + +def _load_fixture_builder() -> Callable[[Path, Path], dict[str, Any]]: + script_path = Path("scripts/build_calc_fixture.py") + spec = spec_from_file_location("build_calc_fixture", script_path) + assert spec is not None and spec.loader is not None + module = module_from_spec(spec) + assert isinstance(module, ModuleType) + spec.loader.exec_module(module) + return cast(Callable[[Path, Path], dict[str, Any]], module.build_fixture) + + +build_fixture = _load_fixture_builder() + + +@requires_libreoffice +def test_builder_regenerates_identical_expected_json(tmp_path: Path) -> None: + fixture = tmp_path / "financial_model.xlsx" + expected = tmp_path / "expected_values.json" + + first = build_fixture(fixture, expected) + first_text = expected.read_text() + second = build_fixture(fixture, expected) + + assert second == first + assert expected.read_text() == first_text + + +def test_expected_values_cover_every_formula_cell() -> None: + expected = json.loads(EXPECTED.read_text()) + + assert set(expected["cells"]) == set(formula_cells(FIXTURE)) + assert 80 <= len(expected["cells"]) <= 140 + assert all( + cell["type"] in {"number", "string", "bool"} + for cell in expected["cells"].values() + ) + + +def test_value_comparison_respects_tolerance_and_scalar_types() -> None: + assert values_match(10.0, 10.0000005) + assert values_match(1_000_000_000.0, 1_000_000_000.5) + assert not values_match(10.0, 10.000002) + assert values_match("exact", "exact") + assert not values_match("exact", "different") + assert values_match(True, True) + assert not values_match(True, 1) + + +@requires_libreoffice +def test_local_wolfxl_and_libreoffice_engines_calculate(tmp_path: Path) -> None: + wolfxl_engine = WolfXLCalcEngine() + if wolfxl_engine.available(): + import wolfxl + + try: + major, minor = (int(part) for part in wolfxl.__version__.split(".")[:2]) + except (AttributeError, ValueError): + major, minor = 0, 0 + if (major, minor) >= (2, 1): + wolfxl_result = wolfxl_engine.calculate( + FIXTURE, tmp_path / "wolfxl.xlsx" + ) + assert wolfxl_result["status"] == "passed", wolfxl_result["reason"] + + libreoffice_result = LibreOfficeCalcEngine().calculate( + FIXTURE, tmp_path / "libreoffice.xlsx" + ) + assert libreoffice_result["status"] == "passed", libreoffice_result["reason"] + + +def test_aspose_engine_reports_unsupported_formulas_without_raising( + tmp_path: Path, +) -> None: + result = AsposeCellsFossCalcEngine().calculate(FIXTURE, tmp_path / "aspose.xlsx") + + assert result["status"] in {"failed", "unavailable"} + assert result["reason"] diff --git a/tests/test_env_fallback_contracts.py b/tests/test_env_fallback_contracts.py new file mode 100644 index 0000000..7efe564 --- /dev/null +++ b/tests/test_env_fallback_contracts.py @@ -0,0 +1,697 @@ +"""Env-independent contracts for optional-dependency harness paths. + +Covers calc-tier status semantics, mutation-suite control flow, modifiable +engine guards, renderers, and the Zavora adapter's payload/error paths on +machines without LibreOffice, aspose-cells-foss, or the Rust helper. +""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import Any + +import openpyxl +import pytest + +from excelbench import modifiable as modifiable_module +from excelbench.harness import calc as calc_module +from excelbench.harness import mutation as mutation_module +from excelbench.harness.adapters import zavora_adapter as zavora_module +from excelbench.harness.adapters.zavora_adapter import ZavoraAdapter +from excelbench.harness.calc import ( + AsposeCellsFossCalcEngine, + LibreOfficeCalcEngine, + ZavoraCalcEngine, + formula_cells, + run_calc_suite, +) +from excelbench.models import CellType, CellValue +from excelbench.modifiable import OpenpyxlEngine, _mutation_target +from excelbench.results.mutation_renderer import render_mutation_report + +REPO_ROOT = Path(__file__).resolve().parents[1] +FIXTURE = REPO_ROOT / "fixtures" / "calc" / "financial_model.xlsx" + + +class _FakeEngine: + def __init__( + self, + name: str, + available: bool = True, + status: str = "passed", + values: dict[str, Any] | None = None, + reason: str | None = None, + raises: Exception | None = None, + ) -> None: + self.name = name + self._available = available + self._status = status + self._values = values or {} + self._reason = reason + self._raises = raises + + def available(self) -> bool: + return self._available + + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + if self._raises is not None: + raise self._raises + return {"status": self._status, "values": self._values, "reason": self._reason} + + +def _expected(cells: dict[str, Any]) -> dict[str, Any]: + return {"oracle": "test-oracle", "cells": cells} + + +def _cell(value: Any, cell_type: str = "number") -> dict[str, Any]: + return {"value": value, "type": cell_type} + + +# -------------------------------------------------------------------------- +# Calc-tier status semantics +# -------------------------------------------------------------------------- + + +def test_calc_suite_marks_partial_match_failed_with_missing_wrong_split( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + values = { + "Sheet1!A1": 1, + "Sheet1!A2": None, + "Sheet1!A3": 99, + } + monkeypatch.setattr( + calc_module, "_engines", lambda: (_FakeEngine("partial", values=values),) + ) + results = run_calc_suite( + FIXTURE, + _expected( + { + "Sheet1!A1": _cell(1), + "Sheet1!A2": _cell(2), + "Sheet1!A3": _cell(3), + "Sheet1!A4": _cell(4), + } + ), + tmp_path, + ) + engine = results["engines"]["partial"] + assert engine["status"] == "failed" + assert engine["matched"] == 1 + assert engine["total"] == 4 + assert "3/4 formula values wrong or missing" in engine["reason"] + assert "2 missing" in engine["reason"] + assert "1 wrong" in engine["reason"] + + +def test_calc_suite_full_match_passes_and_renders( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr( + calc_module, + "_engines", + lambda: ( + _FakeEngine("good", values={"Sheet1!A1": 10}), + _FakeEngine("bad", status="failed", values={}, reason="exploded"), + _FakeEngine( + "absent", + available=False, + values={"Sheet1!A1": 10}, + ), + ), + ) + results = run_calc_suite(FIXTURE, _expected({"Sheet1!A1": _cell(10)}), tmp_path) + assert results["oracle"] == "test-oracle" + assert results["engines"]["good"]["status"] == "passed" + assert results["engines"]["good"]["reason"] is None + assert results["engines"]["bad"]["status"] == "failed" + assert results["engines"]["bad"]["reason"] == "exploded" + assert results["engines"]["absent"]["status"] == "unavailable" + assert results["engines"]["absent"]["reason"] == "absent is unavailable" + + rendered = json.loads((tmp_path / "results.json").read_text()) + assert set(rendered["engines"]) == {"good", "bad", "absent"} + readme = (tmp_path / "README.md").read_text() + assert "good" in readme and "unavailable" in readme.lower() + + +def test_calc_suite_values_must_be_mapping( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + class _ListValuesEngine(_FakeEngine): + def calculate(self, input_path: Path, output_path: Path) -> dict[str, Any]: + result = super().calculate(input_path, output_path) + result["values"] = ["not", "a", "mapping"] + return result + + monkeypatch.setattr(calc_module, "_engines", lambda: (_ListValuesEngine("listy"),)) + results = run_calc_suite(FIXTURE, _expected({"A1": _cell(1)}), tmp_path) + assert results["engines"]["listy"]["status"] == "failed" + assert results["engines"]["listy"]["matched"] == 0 + + +def test_calc_suite_rejects_malformed_expected_payloads(tmp_path: Path) -> None: + with pytest.raises(ValueError, match="cells mapping"): + run_calc_suite(FIXTURE, {"oracle": "x", "cells": [1, 2]}, tmp_path) + with pytest.raises(ValueError, match="has no value"): + run_calc_suite(FIXTURE, _expected({"A1": {"type": "number"}}), tmp_path) + + +def test_calc_suite_engine_exception_is_contained( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr( + calc_module, + "_engines", + lambda: (_FakeEngine("boom", raises=RuntimeError("kaput")),), + ) + results = run_calc_suite(FIXTURE, _expected({"A1": _cell(1)}), tmp_path) + assert results["engines"]["boom"]["status"] == "failed" + + +# -------------------------------------------------------------------------- +# Calc helper contracts +# -------------------------------------------------------------------------- + + +def test_load_expected_accepts_dict_file_and_dir(tmp_path: Path) -> None: + payload = {"oracle": "o", "cells": {"A1": _cell(1)}} + assert calc_module._load_expected(payload) is payload + + file_path = tmp_path / "custom.json" + file_path.write_text(json.dumps(payload)) + assert calc_module._load_expected(file_path) == payload + + (tmp_path / "expected_values.json").write_text(json.dumps(payload)) + assert calc_module._load_expected(tmp_path) == payload + + +def test_committed_calc_fixture_is_formula_dense_and_cache_free() -> None: + references = formula_cells(FIXTURE) + assert len(references) == 133 + + cached = calc_module._read_values(FIXTURE, references[:10], reader="openpyxl") + assert set(cached.values()) == {None} + + +def test_libreoffice_engine_reports_missing_binary( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr(calc_module, "SOFFICE_PATH", Path("/nonexistent/soffice")) + engine = LibreOfficeCalcEngine() + assert engine.available() is False + result = engine.calculate(FIXTURE, tmp_path / "out.xlsx") + assert result["status"] == "unavailable" + assert "not found" in result["reason"] + + reason = calc_module.recalculate_with_libreoffice(FIXTURE, tmp_path / "out.xlsx") + assert reason is not None and "not found" in reason + + +def test_aspose_calc_engine_unavailable_without_package( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setitem(sys.modules, "aspose", None) + assert AsposeCellsFossCalcEngine().available() is False + + +def _fake_oracle_catalog(available: bool) -> Any: + class _Tool: + def is_available(self) -> bool: + return available + + class _Catalog: + def __call__(self, repo_root: Path | None = None) -> dict[str, Any]: + return {"zavora": _Tool()} + + return _Catalog() + + +def test_zavora_calc_engine_unavailable_without_helper( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr( + calc_module, "external_oracle_catalog", _fake_oracle_catalog(False) + ) + engine = ZavoraCalcEngine() + assert engine.available() is False + result = engine.calculate(FIXTURE, tmp_path / "out.xlsx") + assert result["status"] == "unavailable" + assert result["reason"] == "Zavora helper is unavailable" + + +# -------------------------------------------------------------------------- +# Mutation-suite control flow +# -------------------------------------------------------------------------- + + +def _write_template_with_manifest(directory: Path) -> Path: + template = directory / "template.xlsx" + workbook = openpyxl.Workbook() + sheet = workbook.active + assert sheet is not None + sheet.title = "Inputs" + sheet["A1"] = "original" + sheet["B1"] = 1 + workbook.save(template) + manifest = { + "mutation": {"sheet": "Inputs", "cell": "A1", "value": "-landed"}, + "second_mutation": {"sheet": "Inputs", "cell": "B1", "value": 42}, + } + (directory / "manifest.json").write_text(json.dumps(manifest)) + return template + + +class _UnavailableEngine: + name = "ghost" + + def available(self) -> bool: + return False + + def mutate( + self, template: Path, output: Path, mutations: list[dict[str, Any]] + ) -> None: + raise AssertionError("unavailable engines must not run") + + +def test_run_mutation_suite_rejects_zero_repeats(tmp_path: Path) -> None: + template = _write_template_with_manifest(tmp_path) + with pytest.raises(ValueError, match="at least 1"): + mutation_module.run_mutation_suite(template, tmp_path / "out", repeats=0) + + +def test_run_mutation_suite_unavailable_engine_row(tmp_path: Path) -> None: + template = _write_template_with_manifest(tmp_path) + monkey = pytest.MonkeyPatch() + monkey.setattr( + mutation_module, "modifiable_engines", lambda: [_UnavailableEngine()] + ) + try: + results = mutation_module.run_mutation_suite( + template, tmp_path / "out", repeats=1 + ) + finally: + monkey.undo() + row = results["engines"]["ghost"] + assert row["status"] == "unavailable" + assert row["available"] is False + assert row["wall_ms_median"] is None + + +def test_run_mutation_suite_reports_failed_engine( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + template = _write_template_with_manifest(tmp_path) + + def _explode( + engine: Any, + template: Path, + output: Path, + mutations: list[dict[str, Any]], + ) -> tuple[float, float]: + raise RuntimeError("driver crashed") + + monkeypatch.setattr(mutation_module, "_run_subprocess_mutation", _explode) + monkeypatch.setattr( + mutation_module, + "modifiable_engines", + lambda: [_UnavailableEngine.__new__(_UnavailableEngine)], # noqa: E501 + ) + + class _LiveEngine(_UnavailableEngine): + name = "live" + + def available(self) -> bool: + return True + + monkeypatch.setattr(mutation_module, "modifiable_engines", lambda: [_LiveEngine()]) + results = mutation_module.run_mutation_suite(template, tmp_path / "out", repeats=1) + row = results["engines"]["live"] + assert row["status"] == "failed" + assert "driver crashed" in row["details"]["error"] + assert row["preservation_score"] is None + + +def test_run_mutation_suite_passes_when_mutations_land( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + template = _write_template_with_manifest(tmp_path) + + def _apply( + engine: Any, + template: Path, + output: Path, + mutations: list[dict[str, Any]], + ) -> tuple[float, float]: + workbook = openpyxl.load_workbook(template) + try: + for mutation in mutations: + sheet = workbook[str(mutation["sheet"])] + sheet[str(mutation["cell"])] = mutation["value"] + workbook.save(output) + finally: + workbook.close() + return 12.5, 2048.0 + + monkeypatch.setattr(mutation_module, "_run_subprocess_mutation", _apply) + + class _ApplyingEngine(_UnavailableEngine): + name = "applying" + + def available(self) -> bool: + return True + + monkeypatch.setattr( + mutation_module, "modifiable_engines", lambda: [_ApplyingEngine()] + ) + results = mutation_module.run_mutation_suite(template, tmp_path / "out", repeats=2) + row = results["engines"]["applying"] + assert row["status"] == "passed" + assert row["wall_ms_median"] == 12.5 + assert row["peak_rss_kb_median"] == 2048.0 + assert row["preservation_score"] == 100.0 + assert row["details"]["mutations_landed"] is True + + +def test_run_mutation_suite_flags_integrity_when_values_do_not_land( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + template = _write_template_with_manifest(tmp_path) + + def _copy_only( + engine: Any, + template: Path, + output: Path, + mutations: list[dict[str, Any]], + ) -> tuple[float, float]: + import shutil + + shutil.copyfile(template, output) + return 5.0, 1024.0 + + monkeypatch.setattr(mutation_module, "_run_subprocess_mutation", _copy_only) + + class _LazyEngine(_UnavailableEngine): + name = "lazy" + + def available(self) -> bool: + return True + + monkeypatch.setattr(mutation_module, "modifiable_engines", lambda: [_LazyEngine()]) + results = mutation_module.run_mutation_suite(template, tmp_path / "out", repeats=1) + row = results["engines"]["lazy"] + assert row["status"] == "integrity-failed" + assert row["preservation_score"] == 0.0 + assert "did not match" in row["details"]["integrity_failure"] + + +def test_mutations_for_engine_substitutes_placeholder() -> None: + manifest = { + "mutation": {"sheet": "S", "cell": "A1", "value": "-v"}, + "second_mutation": {"sheet": "S", "cell": "B1", "value": 7}, + } + mutations = mutation_module._mutations_for_engine(manifest, "wolfxl") + assert mutations[0]["value"] == "wolfxl-v" + assert mutations[1] == {"sheet": "S", "cell": "B1", "value": 7} + + +def test_mutations_landed_rejects_unreadable_output(tmp_path: Path) -> None: + bogus = tmp_path / "bogus.xlsx" + bogus.write_bytes(b"not an xlsx") + mutations = [{"sheet": "S", "cell": "A1", "value": 1}] + assert mutation_module._mutations_landed(bogus, mutations) is False + + +def test_parse_time_output_extracts_elapsed_and_rss() -> None: + stderr = "\n".join( + [ + " 0.05 real", + " 0.04 user", + " 0.01 sys", + " 4194304 maximum resident set size", + ] + ) + elapsed, rss = mutation_module._parse_time_output(stderr) + assert elapsed == 0.05 + assert rss == 4096.0 + + elapsed_none, rss_none = mutation_module._parse_time_output("garbage") + assert elapsed_none is None and rss_none is None + + +def test_package_integrity_helpers_flag_damage() -> None: + rels_ns = "http://schemas.openxmlformats.org/package/2006/relationships" + parts = { + "xl/_rels/workbook.xml.rels": ( + '' + ).encode(), + "xl/workbook.xml": b"", + "[Content_Types].xml": ( + b'' + ), + } + dangling = mutation_module._dangling_relationships(parts) + assert dangling == ["xl/_rels/workbook.xml.rels: xl/worksheets/sheet1.xml"] + + # workbook.xml has neither an Override nor an xml Default declaration. + missing = mutation_module._missing_content_types(parts) + assert "xl/workbook.xml" in missing + + absent_types = mutation_module._missing_content_types( + {"xl/workbook.xml": b""} + ) + assert absent_types == ["[Content_Types].xml"] + + resolved = mutation_module._relationship_target( + "xl/_rels/x.rels", "worksheets/s.xml" + ) + assert resolved == "xl/worksheets/s.xml" + worksheet_ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" + present = f''.encode() + assert mutation_module._xml_has_element(present, "b") is True + assert mutation_module._xml_has_element(b"", "b") is False + assert mutation_module._xml_has_element(b"not xml <", "b") is False + + +# -------------------------------------------------------------------------- +# Modifiable engine guards +# -------------------------------------------------------------------------- + + +def test_mutation_target_splits_sheet_cell_value() -> None: + sheet, cell, value = _mutation_target({"sheet": "Inputs", "cell": "A1", "value": 5}) + assert (sheet, cell, value) == ("Inputs", "A1", 5) + + +def test_openpyxl_engine_mutates_template(tmp_path: Path) -> None: + template = _write_template_with_manifest(tmp_path) + engine = OpenpyxlEngine() + assert engine.available() is True + output = tmp_path / "mutated.xlsx" + engine.mutate( + template, + output, + [ + {"sheet": "Inputs", "cell": "A1", "value": "changed"}, + {"sheet": "Inputs", "cell": "B1", "value": 9}, + ], + ) + workbook = openpyxl.load_workbook(output) + try: + assert workbook["Inputs"]["A1"].value == "changed" + assert workbook["Inputs"]["B1"].value == 9 + finally: + workbook.close() + + +def test_optional_engines_report_absence(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(modifiable_module, "_aspose_cells_foss", None) + engine = modifiable_module.AsposeFossEngine() + assert engine.available() is False + with pytest.raises(RuntimeError, match="not installed"): + engine.mutate(Path("t.xlsx"), Path("o.xlsx"), []) + + monkeypatch.setattr( + modifiable_module, "external_oracle_catalog", _fake_oracle_catalog(False) + ) + assert modifiable_module.ZavoraEngine().available() is False + + +# -------------------------------------------------------------------------- +# Renderers +# -------------------------------------------------------------------------- + + +def test_mutation_report_renders_all_verdict_branches(tmp_path: Path) -> None: + results: dict[str, Any] = { + "metadata": {"template_sha256": "abc", "repeats": 1, "platform": "Darwin"}, + "engines": { + "perfect": { + "available": True, + "status": "passed", + "wall_ms_median": 100.0, + "peak_rss_kb_median": 2048.0, + "preservation_score": 100.0, + "details": {}, + }, + "lossy": { + "available": True, + "status": "passed", + "wall_ms_median": 200.0, + "peak_rss_kb_median": 4096.0, + "preservation_score": 60.0, + "details": {}, + }, + "broken": { + "available": True, + "status": "integrity-failed", + "wall_ms_median": 300.0, + "peak_rss_kb_median": None, + "preservation_score": 0.0, + "details": {"integrity_failure": "nope"}, + }, + "crashed": { + "available": True, + "status": "failed", + "wall_ms_median": None, + "peak_rss_kb_median": None, + "preservation_score": None, + "details": {"error": "RuntimeError: x"}, + }, + "ghost": { + "available": False, + "status": "unavailable", + "wall_ms_median": None, + "peak_rss_kb_median": None, + "preservation_score": None, + "details": {}, + }, + }, + } + render_mutation_report(results, tmp_path) + persisted: dict[str, Any] = json.loads((tmp_path / "results.json").read_text()) + engines = persisted["engines"] + assert isinstance(engines, dict) + assert set(engines) == set(results["engines"]) + + readme = (tmp_path / "README.md").read_text() + for marker in ("Preserved", "Loss detected", "Mutation integrity failed", "Failed"): + assert marker in readme, marker + + +# -------------------------------------------------------------------------- +# Zavora adapter payload and failure contracts +# -------------------------------------------------------------------------- + + +def test_zavora_adapter_reports_unavailable_helper( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setattr( + zavora_module, "external_oracle_catalog", _fake_oracle_catalog(False) + ) + assert ZavoraAdapter.is_available() is False + + +def _fake_oracle_result( + *, skipped: bool = False, passed: bool = False, payload: Any = None +) -> Any: + class _Result: + def __init__(self) -> None: + self.skipped = skipped + self.passed = passed + self.payload = payload if isinstance(payload, dict) else {} + self.notes = "helper skipped" if skipped else None + self.stderr = "" + self.stdout = "" + + return _Result() + + +def test_zavora_save_raises_when_helper_skips_or_fails( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + adapter = ZavoraAdapter() + monkeypatch.setattr( + zavora_module, + "run_external_oracle", + lambda *a, **k: _fake_oracle_result(skipped=True), + ) + with pytest.raises(FileNotFoundError, match="helper skipped"): + adapter.save_workbook({"sheets": []}, tmp_path / "out.xlsx") + + monkeypatch.setattr( + zavora_module, + "run_external_oracle", + lambda *a, **k: _fake_oracle_result( + passed=False, payload={"message": "rust panic"} + ), + ) + with pytest.raises(RuntimeError, match="rust panic"): + adapter.save_workbook({"sheets": []}, tmp_path / "out.xlsx") + + +def test_zavora_write_cell_value_payload_variants() -> None: + adapter = ZavoraAdapter() + workbook = adapter.create_workbook() + adapter.write_cell_value( + workbook, "S", "A1", CellValue(type=CellType.FORMULA, value=0, formula="=1+1") + ) + adapter.write_cell_value( + workbook, "S", "A2", CellValue(type=CellType.STRING, value="") + ) + adapter.write_cell_value( + workbook, "S", "A3", CellValue(type=CellType.NUMBER, value=7) + ) + assert workbook["cells"][0] == { + "sheet": "S", + "cell": "A1", + "type": "formula", + "formula": "=1+1", + "value": 0, + } + assert workbook["cells"][1]["type"] == "blank" + assert workbook["cells"][1]["value"] is None + assert workbook["cells"][2] == { + "sheet": "S", + "cell": "A3", + "type": str(CellType.NUMBER), + "value": 7, + } + assert {"name": "S"} in workbook["sheets"] + + +def test_zavora_conditional_format_mapping_helpers() -> None: + adapter = ZavoraAdapter() + assert adapter._map_conditional_format_type("colorScale") == "3_color_scale" + assert adapter._map_conditional_format_type("dataBar") == "data_bar" + assert adapter._map_conditional_format_type("expression") == "formula" + assert adapter._map_conditional_format_type("cellIs") == "cell" + assert ( + adapter._map_conditional_format_criteria("expression", None, "=Ref!$A$1>0") + == "Ref!$A$1>0" + ) + assert ( + adapter._map_conditional_format_criteria("cellIs", "greaterThan", None) == ">" + ) + assert ( + adapter._map_conditional_format_criteria("cellIs", "unknownOperator", None) + == ">" + ) + + +def test_zavora_read_operations_raise_structured_unsupported() -> None: + adapter = ZavoraAdapter() + workbook = adapter.create_workbook() + with pytest.raises(NotImplementedError, match="write-only"): + adapter.read_cell_value(workbook, "S", "A1") + with pytest.raises(NotImplementedError, match="write-only"): + adapter.get_sheet_names(workbook) diff --git a/tests/test_external_oracles.py b/tests/test_external_oracles.py index dbddaf2..16f216a 100644 --- a/tests/test_external_oracles.py +++ b/tests/test_external_oracles.py @@ -42,7 +42,10 @@ def test_catalog_lists_planned_external_oracles() -> None: "exceljs", "closedxml", "npoi", + "zavora", } + assert catalog["zavora"].language == "rust" + assert "calculate" in catalog["zavora"].capabilities assert "pivots" in catalog["excelize"].capabilities assert "open_save_validate" in catalog["libreoffice"].capabilities assert "data_validations" in catalog["apache-poi"].capabilities diff --git a/tests/test_mutation_suite.py b/tests/test_mutation_suite.py new file mode 100644 index 0000000..5657b48 --- /dev/null +++ b/tests/test_mutation_suite.py @@ -0,0 +1,201 @@ +"""Tests for the surgical template-mutation benchmark.""" + +from __future__ import annotations + +import hashlib +import shutil +import subprocess +import sys +from pathlib import Path +from zipfile import ZIP_DEFLATED, ZipFile + +import openpyxl +import pytest + +from excelbench.harness.mutation import score_preservation +from excelbench.modifiable import modifiable_engines +from excelbench.results.mutation_renderer import render_mutation_report + +REPO_ROOT = Path(__file__).resolve().parents[1] +BUILDER = REPO_ROOT / "scripts" / "build_mutation_template.py" +TEMPLATE = REPO_ROOT / "fixtures" / "mutation" / "template_corporate_model.xlsx" +SOFFICE = Path(shutil.which("soffice") or "/opt/homebrew/bin/soffice") +requires_libreoffice = pytest.mark.skipif( + not SOFFICE.is_file(), reason="LibreOffice binary not available" +) + + +def _sha256(path: Path) -> str: + """Return the full-file SHA-256 digest.""" + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def _content_types() -> bytes: + """Build minimum valid content type declarations for synthetic packages.""" + return ( + b""" + + + +""" + ) + + +def _relationship_xml(target: str) -> bytes: + """Build a workbook relationship XML part targeting one worksheet.""" + return f""" + + +""".encode() + + +def _write_synthetic_package( + path: Path, + *, + include_custom_xml: bool = True, + table_parts: bool = True, + target: str = "worksheets/sheet1.xml", +) -> None: + """Write a small package that exercises preservation scorer failure modes.""" + sheet_tail = ( + '' + if table_parts + else "" + ) + sheet_xml = ( + '' + f"{sheet_tail}" + ).encode() + parts = { + "[Content_Types].xml": _content_types(), + "_rels/.rels": b'', + "xl/workbook.xml": b"", + "xl/_rels/workbook.xml.rels": _relationship_xml(target), + "xl/worksheets/sheet1.xml": sheet_xml, + "xl/tables/table1.xml": b"", + } + if include_custom_xml: + parts["customXml/item1.xml"] = b"stable" + with ZipFile(path, "w", compression=ZIP_DEFLATED) as archive: + for name, payload in parts.items(): + archive.writestr(name, payload) + + +def test_builder_is_byte_stable() -> None: + """Repeated generation writes the same package bytes.""" + subprocess.run([sys.executable, str(BUILDER)], cwd=REPO_ROOT, check=True) + first_digest = _sha256(TEMPLATE) + subprocess.run([sys.executable, str(BUILDER)], cwd=REPO_ROOT, check=True) + assert _sha256(TEMPLATE) == first_digest + + +@requires_libreoffice +def test_template_opens_in_openpyxl_and_libreoffice(tmp_path: Path) -> None: + """The committed fixture parses and LibreOffice renders it to PDF.""" + workbook = openpyxl.load_workbook(TEMPLATE) + try: + assert workbook.sheetnames == ["Inputs", "Schedule", "Summary"] + assert workbook["Inputs"]["B2"].value is not None + finally: + workbook.close() + + completed = subprocess.run( + [ + str(SOFFICE), + "--headless", + "--convert-to", + "pdf", + "--outdir", + str(tmp_path), + str(TEMPLATE), + ], + text=True, + capture_output=True, + check=False, + ) + assert completed.returncode == 0, completed.stderr + assert (tmp_path / "template_corporate_model.pdf").is_file() + + +def test_preservation_scorer_reports_lost_custom_part(tmp_path: Path) -> None: + """A dropped package part reduces the structural score.""" + template = tmp_path / "template.xlsx" + output = tmp_path / "output.xlsx" + _write_synthetic_package(template) + _write_synthetic_package(output, include_custom_xml=False) + + result = score_preservation(template, output) + + assert "customXml/item1.xml" in result["details"]["lost_parts"] + assert result["details"]["customXml_identical"] is False + assert result["preservation_score"] < 100 + + +def test_preservation_scorer_reports_dangling_relationship(tmp_path: Path) -> None: + """A relationship to a missing worksheet is reported as an integrity error.""" + template = tmp_path / "template.xlsx" + output = tmp_path / "output.xlsx" + _write_synthetic_package(template) + _write_synthetic_package(output, target="worksheets/missing.xml") + + result = score_preservation(template, output) + + assert result["details"]["dangling_rels"] == [ + "xl/_rels/workbook.xml.rels: xl/worksheets/missing.xml" + ] + assert result["preservation_score"] < 100 + + +def test_preservation_scorer_reports_dropped_table_parts(tmp_path: Path) -> None: + """Dropping a worksheet table declaration reduces the element score.""" + template = tmp_path / "template.xlsx" + output = tmp_path / "output.xlsx" + _write_synthetic_package(template) + _write_synthetic_package(output, table_parts=False) + + result = score_preservation(template, output) + + assert any( + entry["element"] == "tableParts" + and entry["present_in_original"] + and not entry["present_in_output"] + for entry in result["details"]["element_diffs"] + ) + assert result["preservation_score"] < 100 + + +def test_engine_registry_exposes_availability_flags() -> None: + """Every supported mutation engine reports an explicit availability flag.""" + engines = {engine.name: engine.available() for engine in modifiable_engines()} + + assert set(engines) == {"openpyxl", "wolfxl", "aspose-cells-foss", "zavora-xlsx"} + assert all(isinstance(available, bool) for available in engines.values()) + + +def test_renderer_writes_comparison_files(tmp_path: Path) -> None: + """The renderer writes machine-readable and concise Markdown reports.""" + results = { + "metadata": { + "template_sha256": "abc", + "repeats": 3, + "timestamp": "2026-01-01T00:00:00Z", + }, + "engines": { + "openpyxl": { + "status": "passed", + "wall_ms_median": 12.5, + "peak_rss_kb_median": 2048.0, + "preservation_score": 90.0, + "details": {"lost_parts": ["customXml/item1.xml"]}, + } + }, + } + + render_mutation_report(results, tmp_path) + + assert (tmp_path / "results.json").is_file() + assert "| openpyxl | 12.500 | 2048.000 | 90.000 | 1 | Loss detected |" in ( + tmp_path / "README.md" + ).read_text(encoding="utf-8") diff --git a/tests/test_tier4_handlers.py b/tests/test_tier4_handlers.py new file mode 100644 index 0000000..653e487 --- /dev/null +++ b/tests/test_tier4_handlers.py @@ -0,0 +1,206 @@ +"""Tests for Tier-4 handlers: sheet_protection, page_setup, chart_anchor. + +Builds the Tier-4 structural fixtures into a temp directory via +scripts/build_tier4_fixtures.py, assembles a benchmark directory from the +generated manifest fragment, and runs the full read + write lanes against +OpenpyxlAdapter — proving the runner dispatch, fixtures, and openpyxl +verifier chain end to end. Also checks that adapters lacking the Tier-4 +methods yield structured failure results instead of crashes. +""" + +from __future__ import annotations + +import importlib.util +import shutil +import sys +from pathlib import Path +from types import ModuleType +from typing import Any + +from excelbench.generator.generate import load_manifest +from excelbench.harness.adapters.base import ReadOnlyAdapter +from excelbench.harness.adapters.openpyxl_adapter import OpenpyxlAdapter +from excelbench.harness.runner import run_benchmark +from excelbench.models import ( + BorderInfo, + CellFormat, + CellValue, + DiagnosticCategory, + LibraryInfo, +) + +REPO_ROOT = Path(__file__).resolve().parent.parent +BUILDER_PATH = REPO_ROOT / "scripts" / "build_tier4_fixtures.py" + +TIER4_FEATURES = ["sheet_protection", "page_setup", "chart_anchor"] +CASE_COUNTS = {"sheet_protection": 3, "page_setup": 3, "chart_anchor": 2} + + +def _load_builder() -> ModuleType: + spec = importlib.util.spec_from_file_location("build_tier4_fixtures", BUILDER_PATH) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + sys.modules["build_tier4_fixtures"] = module + spec.loader.exec_module(module) + return module + + +def _build_bench_dir(tmp_path: Path) -> Path: + """Build Tier-4 fixtures into tmp and assemble a runnable benchmark dir.""" + builder = _load_builder() + fixtures_root = tmp_path / "fixtures" + fragment_path = builder.build_all(fixtures_root) + assert fragment_path.exists() + + bench_dir = tmp_path / "bench" + bench_dir.mkdir() + shutil.copytree(fixtures_root / "tier4", bench_dir / "tier4") + shutil.copy(fragment_path, bench_dir / "manifest.json") + return bench_dir + + +class TestTier4Benchmark: + def test_openpyxl_read_and_write_scores(self, tmp_path: Path) -> None: + bench_dir = _build_bench_dir(tmp_path) + + results = run_benchmark( + bench_dir, adapters=[OpenpyxlAdapter()], features=TIER4_FEATURES + ) + + by_feature = {score.feature: score for score in results.scores} + assert set(by_feature) == set(TIER4_FEATURES) + for feature in TIER4_FEATURES: + score = by_feature[feature] + failures = [r for r in score.test_results if not r.passed] + assert score.read_score == 3, ( + f"{feature} read failures: {[(r.test_case_id, r.actual) for r in failures]}" + ) + assert score.write_score == 3, ( + f"{feature} write failures: {[(r.test_case_id, r.actual) for r in failures]}" + ) + + def test_fragment_loads_as_manifest(self, tmp_path: Path) -> None: + builder = _load_builder() + fragment_path = builder.build_all(tmp_path) + + manifest = load_manifest(fragment_path) + + assert [f.feature for f in manifest.files] == TIER4_FEATURES + for test_file in manifest.files: + assert test_file.tier == 4 + assert test_file.file_format == "xlsx" + for test_file in manifest.files: + assert len(test_file.test_cases) == CASE_COUNTS[test_file.feature] + if test_file.feature == "chart_anchor": + assert all(tc.sheet is None for tc in test_file.test_cases) + else: + assert all( + tc.sheet and tc.sheet.startswith(test_file.feature) + for tc in test_file.test_cases + ) + protection = manifest.files[0] + assert {tc.id for tc in protection.test_cases} == { + "prot_basic", + "prot_password", + "prot_granular", + } + # The write-only password must ride along in the manifest payload. + password_case = next( + tc for tc in protection.test_cases if tc.id == "prot_password" + ) + assert password_case.expected["protection"]["password"] == "bench-secret" + + +class _Tier3OnlyReader(ReadOnlyAdapter): + """Read-only adapter that implements every pre-Tier-4 read and nothing else.""" + + def __init__(self) -> None: + self._inner = OpenpyxlAdapter() + + @property + def info(self) -> LibraryInfo: + return LibraryInfo( + name="tier3-only-reader", + version="0", + language="python", + capabilities={"read"}, + ) + + def open_workbook(self, path: Path) -> Any: + return self._inner.open_workbook(path) + + def close_workbook(self, workbook: Any) -> None: + self._inner.close_workbook(workbook) + + def get_sheet_names(self, workbook: Any) -> list[str]: + return self._inner.get_sheet_names(workbook) + + def read_cell_value(self, workbook: Any, sheet: str, cell: str) -> CellValue: + return self._inner.read_cell_value(workbook, sheet, cell) + + def read_cell_format(self, workbook: Any, sheet: str, cell: str) -> CellFormat: + return self._inner.read_cell_format(workbook, sheet, cell) + + def read_cell_border(self, workbook: Any, sheet: str, cell: str) -> BorderInfo: + return self._inner.read_cell_border(workbook, sheet, cell) + + def read_row_height(self, workbook: Any, sheet: str, row: int) -> float | None: + return self._inner.read_row_height(workbook, sheet, row) + + def read_column_width(self, workbook: Any, sheet: str, column: str) -> float | None: + return self._inner.read_column_width(workbook, sheet, column) + + def read_merged_ranges(self, workbook: Any, sheet: str) -> list[str]: + return self._inner.read_merged_ranges(workbook, sheet) + + def read_conditional_formats( + self, workbook: Any, sheet: str + ) -> list[dict[str, Any]]: + return self._inner.read_conditional_formats(workbook, sheet) + + def read_data_validations(self, workbook: Any, sheet: str) -> list[dict[str, Any]]: + return self._inner.read_data_validations(workbook, sheet) + + def read_hyperlinks(self, workbook: Any, sheet: str) -> list[dict[str, Any]]: + return self._inner.read_hyperlinks(workbook, sheet) + + def read_images(self, workbook: Any, sheet: str) -> list[dict[str, Any]]: + return self._inner.read_images(workbook, sheet) + + def read_pivot_tables(self, workbook: Any, sheet: str) -> list[dict[str, Any]]: + return self._inner.read_pivot_tables(workbook, sheet) + + def read_comments(self, workbook: Any, sheet: str) -> list[dict[str, Any]]: + return self._inner.read_comments(workbook, sheet) + + def read_freeze_panes(self, workbook: Any, sheet: str) -> dict[str, Any]: + return self._inner.read_freeze_panes(workbook, sheet) + + +class TestUnsupportedAdapter: + def test_missing_tier4_methods_yield_structured_failures( + self, tmp_path: Path + ) -> None: + bench_dir = _build_bench_dir(tmp_path) + adapter = _Tier3OnlyReader() + + results = run_benchmark(bench_dir, adapters=[adapter], features=TIER4_FEATURES) + + assert len(results.scores) == 3 + for score in results.scores: + read_results = [ + r for r in score.test_results if r.operation.value == "read" + ] + assert len(read_results) == CASE_COUNTS[score.feature] + for result in read_results: + assert result.passed is False + assert "does not implement" in str(result.actual.get("error", "")) + assert result.diagnostics, ( + f"{score.feature}/{result.test_case_id} lacks diagnostics" + ) + assert ( + result.diagnostics[0].category + == DiagnosticCategory.UNSUPPORTED_FEATURE + ) + # Read-only adapter: the write lane is skipped, not scored. + assert score.write_score is None diff --git a/tests/test_wolfxl_adapter_roundtrip.py b/tests/test_wolfxl_adapter_roundtrip.py new file mode 100644 index 0000000..7df91cd --- /dev/null +++ b/tests/test_wolfxl_adapter_roundtrip.py @@ -0,0 +1,211 @@ +"""Round-trip contracts for the WolfxlAdapter through the public WolfXL API. + +Verified against WolfXL 2.0.1 (PyPI) and 2.1.0 (local wheel): every +covered operation behaves identically on both versions. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import Any + +import pytest + +wolfxl = pytest.importorskip("wolfxl", reason="wolfxl not installed") + +from excelbench.harness.adapters import WolfxlAdapter # noqa: E402 +from excelbench.models import ( # noqa: E402 + BorderEdge, + BorderInfo, + BorderStyle, + CellFormat, + CellType, + CellValue, +) + + +@pytest.fixture +def adapter() -> Any: + assert WolfxlAdapter is not None + return WolfxlAdapter() + + +def _string(value: str) -> CellValue: + return CellValue(type=CellType.STRING, value=value) + + +def _number(value: float) -> CellValue: + return CellValue(type=CellType.NUMBER, value=value) + + +def _build_basic_workbook(adapter: Any) -> Any: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "Data") + adapter.write_cell_value(workbook, "Data", "A1", _string("hello")) + adapter.write_cell_value(workbook, "Data", "B1", _number(7)) + adapter.write_cell_value(workbook, "Data", "B2", _number(2.5)) + return workbook + + +def test_value_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = _build_basic_workbook(adapter) + path = tmp_path / "values.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + assert adapter.get_sheet_names(reopened) == ["Data"] + assert adapter.read_cell_value(reopened, "Data", "A1").value == "hello" + assert adapter.read_cell_value(reopened, "Data", "B1").value == 7 + assert adapter.read_cell_value(reopened, "Data", "B2").value == 2.5 + finally: + adapter.close_workbook(reopened) + + +def test_boolean_and_blank_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "S") + adapter.write_cell_value( + workbook, "S", "A1", CellValue(type=CellType.BOOLEAN, value=True) + ) + adapter.write_cell_value( + workbook, "S", "A2", CellValue(type=CellType.BLANK, value=None) + ) + path = tmp_path / "bool.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + assert adapter.read_cell_value(reopened, "S", "A1").value is True + assert adapter.read_cell_value(reopened, "S", "A2").value is None + finally: + adapter.close_workbook(reopened) + + +def test_opened_workbook_tracks_its_source_path(adapter: Any, tmp_path: Path) -> None: + workbook = _build_basic_workbook(adapter) + path = tmp_path / "bound.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + assert adapter._workbook_paths.get(id(reopened)) == path + finally: + adapter.close_workbook(reopened) + + +def test_format_border_dimension_merge_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "F") + adapter.write_cell_value(workbook, "F", "A1", _number(1)) + adapter.write_cell_format( + workbook, + "F", + "A1", + CellFormat(bold=True, font_size=14.0, bg_color="#FFFF0000"), + ) + adapter.write_cell_border( + workbook, + "F", + "A1", + BorderInfo(bottom=BorderEdge(style=BorderStyle.MEDIUM, color="#FF0000")), + ) + adapter.set_row_height(workbook, "F", 1, 30.5) + adapter.set_column_width(workbook, "F", "A", 42.0) + adapter.merge_cells(workbook, "F", "A3:B4") + path = tmp_path / "formatted.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + cell_format = adapter.read_cell_format(reopened, "F", "A1") + assert cell_format.bold is True + assert cell_format.font_size == 14.0 + + border = adapter.read_cell_border(reopened, "F", "A1") + assert border.bottom is not None + assert border.bottom.style == BorderStyle.MEDIUM + + assert adapter.read_row_height(reopened, "F", 1) == 30.5 + assert adapter.read_column_width(reopened, "F", "A") == 42.0 + assert "A3:B4" in adapter.read_merged_ranges(reopened, "F") + finally: + adapter.close_workbook(reopened) + + +def test_formula_text_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "C") + adapter.write_cell_value(workbook, "C", "A1", _number(2)) + adapter.write_cell_value(workbook, "C", "A2", _number(3)) + adapter.write_cell_value( + workbook, + "C", + "A3", + CellValue(type=CellType.FORMULA, value=5, formula="=A1+A2"), + ) + path = tmp_path / "formula.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + formula_cell = adapter.read_cell_value(reopened, "C", "A3") + assert formula_cell.formula == "=A1+A2" + finally: + adapter.close_workbook(reopened) + + +def test_structure_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "S") + adapter.write_cell_value(workbook, "S", "B2", _number(42)) + adapter.set_freeze_panes(workbook, "S", {"mode": "freeze", "top_left_cell": "B2"}) + adapter.add_named_range( + workbook, "S", {"name": "SingleCell", "refers_to": "S!$B$2"} + ) + adapter.add_comment( + workbook, "S", {"cell": "A2", "text": "note", "author": "tester"} + ) + adapter.add_table(workbook, "S", {"name": "T1", "ref": "A1:A2"}) + path = tmp_path / "structure.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + assert adapter.read_freeze_panes(reopened, "S") == { + "mode": "freeze", + "top_left_cell": "B2", + } + ranges = adapter.read_named_ranges(reopened, "S") + assert any(item["name"] == "SingleCell" for item in ranges) + comments = adapter.read_comments(reopened, "S") + assert comments[0]["text"] == "note" + tables = adapter.read_tables(reopened, "S") + assert tables[0]["name"] == "T1" + finally: + adapter.close_workbook(reopened) + + +def test_hyperlink_round_trip(adapter: Any, tmp_path: Path) -> None: + workbook = adapter.create_workbook() + adapter.add_sheet(workbook, "L") + adapter.write_cell_value(workbook, "L", "A1", _string("site")) + adapter.add_hyperlink( + workbook, + "L", + { + "cell": "A1", + "target": "https://example.com", + "display": "Example", + "internal": False, + }, + ) + path = tmp_path / "links.xlsx" + adapter.save_workbook(workbook, path) + + reopened = adapter.open_workbook(path) + try: + links = adapter.read_hyperlinks(reopened, "L") + assert any(link.get("target") == "https://example.com" for link in links) + finally: + adapter.close_workbook(reopened) diff --git a/tests/test_zavora_adapter.py b/tests/test_zavora_adapter.py new file mode 100644 index 0000000..90397ba --- /dev/null +++ b/tests/test_zavora_adapter.py @@ -0,0 +1,123 @@ +"""Pure-Python payload tests for the Zavora write adapter.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from excelbench.harness.adapters.zavora_adapter import ZavoraAdapter +from excelbench.harness.external_oracles import ( + ExternalOracleRequest, + ExternalOracleResult, +) +from excelbench.models import CellType, CellValue + + +@pytest.fixture +def zavora() -> ZavoraAdapter: + return ZavoraAdapter() + + +def test_info_declares_write_only_capability(zavora: ZavoraAdapter) -> None: + assert zavora.info.name == "zavora-xlsx" + assert zavora.info.version == "0.1.2" + assert zavora.info.language == "rust" + assert zavora.info.capabilities == {"write"} + assert zavora.can_write() + assert not zavora.can_read() + + +def test_cell_value_and_formula_entries(zavora: ZavoraAdapter) -> None: + workbook = zavora.create_workbook() + zavora.write_cell_value( + workbook, "Data", "A1", CellValue(type=CellType.NUMBER, value=42) + ) + zavora.write_cell_value( + workbook, + "Data", + "B1", + CellValue(type=CellType.FORMULA, value="=A1*2", formula="=A1*2"), + ) + + assert workbook["sheets"] == [{"name": "Data"}] + assert workbook["cells"] == [ + {"sheet": "Data", "cell": "A1", "type": "number", "value": 42}, + { + "sheet": "Data", + "cell": "B1", + "type": "formula", + "formula": "=A1*2", + "value": "=A1*2", + }, + ] + + +def test_table_merge_and_freeze_payloads(zavora: ZavoraAdapter) -> None: + workbook = zavora.create_workbook() + zavora.merge_cells(workbook, "Data", "A1:B1") + zavora.set_freeze_panes( + workbook, "Data", {"freeze": {"mode": "freeze", "y_split": 1}} + ) + zavora.add_table( + workbook, + "Data", + {"table": {"name": "Items", "ref": "A1:B3", "columns": ["Name", "Amount"]}}, + ) + + assert workbook["merges"] == [{"sheet": "Data", "range": "A1:B1"}] + assert workbook["panes"] == [{"sheet": "Data", "mode": "freeze", "y_split": 1}] + assert workbook["tables"] == [ + { + "sheet": "Data", + "range": "A1:B3", + "name": "Items", + "style": None, + "show_header_row": True, + "show_row_stripes": True, + "totals_row": False, + "columns": ["Name", "Amount"], + "autofilter": False, + } + ] + + +def test_save_invokes_write_fixture_request( + zavora: ZavoraAdapter, monkeypatch: pytest.MonkeyPatch, tmp_path: Path +) -> None: + captured: dict[str, object] = {} + + def fake_run( + tool: object, request: object, **kwargs: object + ) -> ExternalOracleResult: + captured["tool"] = tool + captured["request"] = request + captured["kwargs"] = kwargs + return ExternalOracleResult( + tool_name="zavora", + passed=True, + skipped=False, + returncode=0, + stdout='{"ok": true}', + stderr="", + payload={"ok": True}, + ) + + monkeypatch.setattr( + "excelbench.harness.adapters.zavora_adapter.run_external_oracle", fake_run + ) + output_path = tmp_path / "result.xlsx" + workbook = zavora.create_workbook() + zavora.write_cell_value( + workbook, "Data", "A1", CellValue(type=CellType.STRING, value="hello") + ) + + zavora.save_workbook(workbook, output_path) + + request = captured["request"] + assert isinstance(request, ExternalOracleRequest) + assert request.fixture_id == "zavora-adapter" + assert request.operation == "write_fixture" + assert request.output_path == output_path + assert request.payload is workbook + assert captured["kwargs"] == {"timeout_seconds": 300} diff --git a/tools/external-oracles/zavora/.gitignore b/tools/external-oracles/zavora/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/tools/external-oracles/zavora/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tools/external-oracles/zavora/Cargo.toml b/tools/external-oracles/zavora/Cargo.toml new file mode 100644 index 0000000..e774a31 --- /dev/null +++ b/tools/external-oracles/zavora/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "zavora-oracle" +version = "0.1.0" +edition = "2021" +publish = false + +[[bin]] +name = "zavora-oracle" +path = "src/main.rs" + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +zavora-xlsx = "0.1.2" diff --git a/tools/external-oracles/zavora/src/main.rs b/tools/external-oracles/zavora/src/main.rs new file mode 100644 index 0000000..753fae7 --- /dev/null +++ b/tools/external-oracles/zavora/src/main.rs @@ -0,0 +1,723 @@ +use std::collections::BTreeMap; +use std::fs; +use std::io::{self, Read}; +use std::path::Path; + +use serde::Deserialize; +use serde_json::{json, Map, Value}; +use zavora_xlsx::{ + Align, BorderStyle, CellValue, Chart, ChartType, Format, Table, TableColumn, TableStyle, + Underline, Workbook, +}; + +#[derive(Debug, Deserialize)] +struct OracleRequest { + fixture_id: String, + operation: String, + #[serde(default)] + payload: Value, + input_path: Option, + output_path: Option, +} + +fn main() { + let response = run().unwrap_or_else(|message| failure(None, None, message)); + println!("{response}"); +} + +fn run() -> Result { + let mut input = String::new(); + io::stdin() + .read_to_string(&mut input) + .map_err(|error| format!("read request: {error}"))?; + let request: OracleRequest = + serde_json::from_str(&input).map_err(|error| format!("decode request: {error}"))?; + + match request.operation.as_str() { + "write_fixture" => write_fixture(&request), + "mutate" => mutate(&request), + "calculate" => calculate(&request), + operation => Err(format!("unsupported operation {operation:?}")), + } +} + +fn failure(fixture_id: Option<&str>, operation: Option<&str>, message: String) -> Value { + let mut response = Map::new(); + response.insert("ok".into(), Value::Bool(false)); + response.insert("error".into(), Value::String("zavora_oracle_failed".into())); + response.insert("message".into(), Value::String(message)); + if let Some(fixture_id) = fixture_id { + response.insert("fixture_id".into(), Value::String(fixture_id.into())); + } + if let Some(operation) = operation { + response.insert("operation".into(), Value::String(operation.into())); + } + Value::Object(response) +} + +fn write_fixture(request: &OracleRequest) -> Result { + let output_path = required_path(request.output_path.as_deref(), "write_fixture requires output_path")?; + ensure_supported_payload(&request.payload)?; + + let mut workbook = Workbook::new(); + configure_sheets(&mut workbook, &request.payload)?; + apply_merges(&mut workbook, &request.payload)?; + apply_cells(&mut workbook, &request.payload)?; + apply_formats(&mut workbook, &request.payload)?; + apply_borders(&mut workbook, &request.payload)?; + apply_columns(&mut workbook, &request.payload)?; + apply_row_heights(&mut workbook, &request.payload)?; + apply_hyperlinks(&mut workbook, &request.payload)?; + apply_comments(&mut workbook, &request.payload)?; + apply_panes(&mut workbook, &request.payload)?; + apply_named_ranges(&mut workbook, &request.payload)?; + apply_tables(&mut workbook, &request.payload)?; + apply_charts(&mut workbook, &request.payload)?; + + create_parent(output_path)?; + workbook + .save(output_path) + .map_err(|error| format!("save workbook: {error}"))?; + + Ok(json!({ + "ok": true, + "fixture_id": request.fixture_id, + "operation": request.operation, + "output_path": output_path, + "tool": "zavora-xlsx", + "counts": payload_counts(&request.payload), + })) +} + +fn mutate(request: &OracleRequest) -> Result { + let input_path = required_path(request.input_path.as_deref(), "mutate requires input_path")?; + let output_path = required_path(request.output_path.as_deref(), "mutate requires output_path")?; + let payload = object(&request.payload, "mutate payload")?; + let sheet = required_string(payload, "sheet")?; + let cell = required_string(payload, "cell")?; + let value = payload + .get("value") + .ok_or_else(|| "mutate payload requires value".to_string())?; + let (row, col) = parse_cell(cell)?; + let mut workbook = Workbook::open(input_path).map_err(|error| format!("open workbook: {error}"))?; + write_json_value(workbook.worksheet_by_name(sheet).map_err(|error| error.to_string())?, row, col, value)?; + create_parent(output_path)?; + workbook + .save(output_path) + .map_err(|error| format!("save workbook: {error}"))?; + Ok(json!({ + "ok": true, + "fixture_id": request.fixture_id, + "operation": request.operation, + "output_path": output_path, + "tool": "zavora-xlsx", + })) +} + +fn calculate(request: &OracleRequest) -> Result { + let input_path = required_path(request.input_path.as_deref(), "calculate requires input_path")?; + let output_path = required_path(request.output_path.as_deref(), "calculate requires output_path")?; + let mut workbook = Workbook::open(input_path).map_err(|error| format!("open workbook: {error}"))?; + let formula_cells = collect_formula_cells(&mut workbook)?; + workbook + .recalculate() + .map_err(|error| format!("recalculate workbook: {error}"))?; + let mut values = BTreeMap::new(); + for (sheet_name, row, col) in formula_cells { + let value = workbook + .worksheet_by_name(&sheet_name) + .map_err(|error| error.to_string())? + .read_cell(row, col); + values.insert( + format!("{sheet_name}!{}", cell_name(row, col)), + calculated_value_to_json(&value), + ); + } + create_parent(output_path)?; + workbook + .save(output_path) + .map_err(|error| format!("save workbook: {error}"))?; + Ok(json!({ + "ok": true, + "fixture_id": request.fixture_id, + "operation": request.operation, + "output_path": output_path, + "tool": "zavora-xlsx", + "values": values, + })) +} + +fn collect_formula_cells(workbook: &mut Workbook) -> Result, String> { + let sheet_names: Vec = workbook.sheet_names().into_iter().map(str::to_owned).collect(); + let mut formulas = Vec::new(); + for sheet_name in sheet_names { + let range = { + let sheet = workbook + .worksheet_by_name(&sheet_name) + .map_err(|error| error.to_string())?; + sheet.used_range() + }; + if let Some((first_row, first_col, last_row, last_col)) = range { + let sheet = workbook + .worksheet_by_name(&sheet_name) + .map_err(|error| error.to_string())?; + for row in first_row..=last_row { + for col in first_col..=last_col { + if matches!(sheet.read_cell(row, col), CellValue::Formula { .. }) { + formulas.push((sheet_name.clone(), row, col)); + } + } + } + } + } + Ok(formulas) +} + +fn calculated_value_to_json(value: &CellValue) -> Value { + match value { + CellValue::Formula { cached_value, .. } => calculated_value_to_json(cached_value), + CellValue::Number(number) => json!(number), + CellValue::String(text) | CellValue::Error(text) => json!(text), + CellValue::Bool(boolean) => json!(boolean), + CellValue::DateTime(date_time) => json!(date_time.serial()), + CellValue::Empty | CellValue::RichText(_) => Value::Null, + } +} + +fn configure_sheets(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + let sheets = array(payload, "sheets")?; + if sheets.is_empty() { + return Ok(()); + } + for (index, sheet) in sheets.iter().enumerate() { + let name = required_string(object(sheet, "sheet entry")?, "name")?; + if index == 0 { + workbook + .rename_worksheet(0, name) + .map_err(|error| format!("rename first sheet: {error}"))?; + } else { + workbook + .add_worksheet_with_name(name) + .map_err(|error| format!("add sheet {name:?}: {error}"))?; + } + } + Ok(()) +} + +fn apply_cells(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "cells")? { + let cell = object(entry, "cell entry")?; + let sheet_name = required_string(cell, "sheet")?; + let address = required_string(cell, "cell")?; + let (row, col) = parse_cell(address)?; + let sheet = workbook + .worksheet_by_name(sheet_name) + .map_err(|error| format!("cell {sheet_name}!{address}: {error}"))?; + let cell_type = optional_string(cell, "type").unwrap_or(""); + if cell_type == "blank" { + sheet + .write_blank(row, col, &Format::new()) + .map_err(|error| error.to_string())?; + } else if cell_type == "formula" || cell.get("formula").is_some_and(Value::is_string) { + let formula = optional_string(cell, "formula") + .or_else(|| cell.get("value").and_then(Value::as_str)) + .ok_or_else(|| format!("formula cell {sheet_name}!{address} requires formula or string value"))?; + sheet + .write_formula(row, col, formula) + .map_err(|error| error.to_string())?; + } else if matches!(cell_type, "date" | "datetime" | "error") { + return Err(format!("unsupported cell type {cell_type:?} at {sheet_name}!{address}")); + } else { + let value = cell.get("value").unwrap_or(&Value::Null); + write_json_value(sheet, row, col, value)?; + } + } + Ok(()) +} + +fn write_json_value( + sheet: &mut zavora_xlsx::Worksheet, + row: u32, + col: u16, + value: &Value, +) -> Result<(), String> { + match value { + Value::Null => sheet.write_blank(row, col, &Format::new()), + Value::Bool(boolean) => sheet.write(row, col, *boolean), + Value::Number(number) => sheet.write( + row, + col, + number + .as_f64() + .ok_or_else(|| "cell number cannot be represented as f64".to_string())?, + ), + Value::String(text) => sheet.write(row, col, text.as_str()), + Value::Array(_) | Value::Object(_) => { + return Err("cell value must be number, string, boolean, or null".into()) + } + } + .map(|_| ()) + .map_err(|error| format!("write cell: {error}")) +} + +fn apply_formats(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "formats")? { + let spec = object(entry, "format entry")?; + let sheet_name = required_string(spec, "sheet")?; + let address = required_string(spec, "cell")?; + let (row, col) = parse_cell(address)?; + let format = build_format(spec)?; + workbook + .worksheet_by_name(sheet_name) + .map_err(|error| error.to_string())? + .set_cell_format(row, col, &format) + .map_err(|error| format!("set format {sheet_name}!{address}: {error}"))?; + } + Ok(()) +} + +fn apply_borders(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "borders")? { + let spec = object(entry, "border entry")?; + let sheet_name = required_string(spec, "sheet")?; + let address = required_string(spec, "cell")?; + let border = object( + spec.get("border").ok_or_else(|| "border entry requires border".to_string())?, + "border", + )?; + let mut format = Format::new(); + for (side, apply) in [ + ("top", Format::border_top as fn(Format, BorderStyle) -> Format), + ("bottom", Format::border_bottom as fn(Format, BorderStyle) -> Format), + ("left", Format::border_left as fn(Format, BorderStyle) -> Format), + ("right", Format::border_right as fn(Format, BorderStyle) -> Format), + ] { + if let Some(side_value) = border.get(side) { + let side_spec = object(side_value, "border side")?; + let style = optional_string(side_spec, "style").unwrap_or("none"); + format = apply(format, border_style(style)?); + if let Some(color) = optional_string(side_spec, "color") { + format = match side { + "top" => format.border_top_color(color), + "bottom" => format.border_bottom_color(color), + "left" => format.border_left_color(color), + "right" => format.border_right_color(color), + _ => format, + }; + } + } + } + let (row, col) = parse_cell(address)?; + workbook + .worksheet_by_name(sheet_name) + .map_err(|error| error.to_string())? + .set_cell_format(row, col, &format) + .map_err(|error| format!("set border {sheet_name}!{address}: {error}"))?; + } + Ok(()) +} + +fn build_format(spec: &Map) -> Result { + let mut format = Format::new(); + if optional_bool(spec, "bold") == Some(true) { format = format.bold(); } + if optional_bool(spec, "italic") == Some(true) { format = format.italic(); } + if optional_bool(spec, "strikethrough") == Some(true) { format = format.strikethrough(); } + if let Some(underline) = optional_string(spec, "underline") { + format = format.underline(match underline { + "none" | "" => Underline::None, + "single" => Underline::Single, + "double" => Underline::Double, + _ => return Err(format!("unsupported underline {underline:?}")), + }); + } + if let Some(name) = optional_string(spec, "font_name") { format = format.font_name(name); } + if let Some(size) = optional_number(spec, "font_size") { format = format.font_size(size); } + if let Some(color) = optional_string(spec, "font_color") { format = format.font_color(color); } + if let Some(color) = optional_string(spec, "bg_color") { format = format.background_color(color); } + if let Some(number_format) = optional_string(spec, "number_format") { format = format.num_format(number_format); } + if let Some(horizontal) = optional_string(spec, "h_align") { format = format.align(horizontal_alignment(horizontal)?); } + if let Some(vertical) = optional_string(spec, "v_align") { format = format.align(vertical_alignment(vertical)?); } + if optional_bool(spec, "wrap") == Some(true) { format = format.text_wrap(); } + if let Some(rotation) = optional_number(spec, "rotation") { format = format.rotation(rotation as i16); } + if let Some(indent) = optional_number(spec, "indent") { format = format.indent(indent as u8); } + Ok(format) +} + +fn apply_columns(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "columns")? { + let spec = object(entry, "column entry")?; + let sheet_name = required_string(spec, "sheet")?; + let start = required_string(spec, "start")?; + let end = required_string(spec, "end")?; + let width = required_number(spec, "width")?; + let start_col = parse_column(start)?; + let end_col = parse_column(end)?; + if start_col > end_col { return Err(format!("invalid column range {start}:{end}")); } + let sheet = workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())?; + for col in start_col..=end_col { + sheet.set_column_width(col, width).map_err(|error| error.to_string())?; + } + } + Ok(()) +} + +fn apply_row_heights(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "row_heights")? { + let spec = object(entry, "row height entry")?; + let sheet_name = required_string(spec, "sheet")?; + let row = required_u32(spec, "row")?.checked_sub(1).ok_or_else(|| "row must be positive".to_string())?; + let height = required_number(spec, "height")?; + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .set_row_height(row, height).map_err(|error| error.to_string())?; + } + Ok(()) +} + +fn apply_merges(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "merges")? { + let spec = object(entry, "merge entry")?; + let sheet_name = required_string(spec, "sheet")?; + let range = required_string(spec, "range")?; + let (first_row, first_col, last_row, last_col) = parse_range(range)?; + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .merge_range(first_row, first_col, last_row, last_col, "", &Format::new()) + .map_err(|error| format!("merge {sheet_name}!{range}: {error}"))?; + } + Ok(()) +} + +fn apply_hyperlinks(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "hyperlinks")? { + let spec = object(entry, "hyperlink entry")?; + if spec.get("tooltip").is_some_and(|value| !value.is_null() && value != "") { + return Err("unsupported hyperlink part: tooltip".into()); + } + let sheet_name = required_string(spec, "sheet")?; + let address = required_string(spec, "cell")?; + let target = required_string(spec, "target")?; + let display = optional_string(spec, "display").unwrap_or(""); + let (row, col) = parse_cell(address)?; + let sheet = workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())?; + if optional_bool(spec, "internal") == Some(true) { + sheet.write_internal_link(row, col, target, display).map_err(|error| error.to_string())?; + } else { + sheet.write_url(row, col, target, display).map_err(|error| error.to_string())?; + } + } + Ok(()) +} + +fn apply_comments(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "comments")? { + let spec = object(entry, "comment entry")?; + let sheet_name = required_string(spec, "sheet")?; + let address = required_string(spec, "cell")?; + let text = required_string(spec, "text")?; + let author = optional_string(spec, "author").unwrap_or("Author"); + let (row, col) = parse_cell(address)?; + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .add_comment_with_author(row, col, text, author); + } + Ok(()) +} + +fn apply_panes(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "panes")? { + let spec = object(entry, "pane entry")?; + if let Some(mode) = optional_string(spec, "mode") { + if mode != "" && mode != "freeze" { return Err(format!("unsupported pane mode {mode:?}")); } + } + if spec.get("top_left_cell").is_some_and(|value| !value.is_null() && value != "") { + return Err("unsupported pane part: top_left_cell".into()); + } + let sheet_name = required_string(spec, "sheet")?; + let row = optional_u32(spec, "y_split").unwrap_or(0); + let col = optional_u16(spec, "x_split").unwrap_or(0); + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .set_freeze_panes(row, col).map_err(|error| error.to_string())?; + } + Ok(()) +} + +fn apply_named_ranges(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "named_ranges")? { + let spec = object(entry, "named range entry")?; + let name = required_string(spec, "name")?; + let formula = required_string(spec, "refers_to")?; + if optional_string(spec, "scope") == Some("sheet") { + let sheet_name = required_string(spec, "sheet")?; + let sheet_index = workbook.sheet_names().iter().position(|candidate| *candidate == sheet_name) + .ok_or_else(|| format!("named range sheet {sheet_name:?} does not exist"))?; + workbook.define_name_scoped(name, formula, sheet_index); + } else { + workbook.define_name(name, formula); + } + } + Ok(()) +} + +fn apply_tables(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "tables")? { + let spec = object(entry, "table entry")?; + if optional_bool(spec, "show_header_row") == Some(false) { + return Err("unsupported table part: show_header_row=false".into()); + } + if optional_bool(spec, "show_row_stripes") == Some(false) { + return Err("unsupported table part: show_row_stripes=false".into()); + } + let sheet_name = required_string(spec, "sheet")?; + let range = required_string(spec, "range")?; + let (first_row, first_col, last_row, last_col) = parse_range(range)?; + let mut table = Table::new(); + if let Some(name) = optional_string(spec, "name") { table.set_name(name); } + if let Some(style) = optional_string(spec, "style") { table.set_style(parse_table_style(style)?); } + table.set_total_row(optional_bool(spec, "totals_row").unwrap_or(false)); + table.set_autofilter(optional_bool(spec, "autofilter").unwrap_or(true)); + let columns: Result, String> = object_array(spec, "columns")?.iter() + .map(|value| value.as_str().map(TableColumn::new).ok_or_else(|| "table columns must be strings".to_string())) + .collect(); + table.set_columns(&columns?); + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .add_table(first_row, first_col, last_row, last_col, &table) + .map_err(|error| format!("add table {sheet_name}!{range}: {error}"))?; + } + Ok(()) +} + +fn apply_charts(workbook: &mut Workbook, payload: &Value) -> Result<(), String> { + for entry in array(payload, "charts")? { + let spec = object(entry, "chart entry")?; + if spec.get("vary_colors").is_some_and(|value| !value.is_null()) { + return Err("unsupported chart part: vary_colors".into()); + } + let sheet_name = required_string(spec, "sheet")?; + let address = required_string(spec, "cell")?; + let chart_type = parse_chart_type(required_string(spec, "type")?)?; + let (row, col) = parse_cell(address)?; + let mut chart = Chart::new(chart_type); + if let Some(title) = optional_string(spec, "title") { chart.set_title(title); } + if let Some(width) = optional_u32(spec, "width") { chart.set_width(width); } + if let Some(height) = optional_u32(spec, "height") { chart.set_height(height); } + if let Some(alt_text) = optional_string(spec, "alt_text") { chart.set_alt_text(optional_string(spec, "name").unwrap_or("Chart"), alt_text); } + let series = object_array(spec, "series")?; + if series.is_empty() { + let values = required_string(spec, "values")?; + let item = chart.add_series(); + item.set_values(values); + if let Some(categories) = optional_string(spec, "categories") { item.set_categories(categories); } + if let Some(name) = optional_string(spec, "name") { item.set_name(name); } + item.set_data_labels(optional_bool(spec, "show_values").unwrap_or(false)); + } else { + for series_spec in series { + let series_object = object(series_spec, "chart series")?; + let item = chart.add_series(); + item.set_values(required_string(series_object, "values")?); + if let Some(categories) = optional_string(series_object, "categories") { item.set_categories(categories); } + if let Some(name) = optional_string(series_object, "name") { item.set_name(name); } + if let Some(color) = optional_string(series_object, "fill_color") { item.set_color(color); } + item.set_data_labels(optional_bool(spec, "show_values").unwrap_or(false)); + for point in object_array(series_object, "data_points")? { + let point = object(point, "chart data point")?; + if let Some(color) = optional_string(point, "fill_color") { + item.set_point_color(required_u32(point, "index")? as usize, color); + } + } + } + } + workbook.worksheet_by_name(sheet_name).map_err(|error| error.to_string())? + .insert_chart(row, col, &chart).map_err(|error| error.to_string())?; + } + Ok(()) +} + +fn ensure_supported_payload(payload: &Value) -> Result<(), String> { + let root = object(payload, "write payload")?; + for part in ["validations", "conditional_formats", "pivots", "slicers", "pictures"] { + if !object_array(root, part)?.is_empty() { + return Err(format!("unsupported payload part: {part}")); + } + } + Ok(()) +} + +fn payload_counts(payload: &Value) -> Value { + let mut counts = Map::new(); + for name in [ + "sheets", "cells", "formats", "borders", "merges", "row_heights", "validations", + "hyperlinks", "comments", "panes", "named_ranges", "tables", "conditional_formats", + "charts", "pivots", "slicers", "pictures", + ] { + let count = payload.get(name).and_then(Value::as_array).map_or(0, Vec::len); + counts.insert(name.into(), json!(count)); + } + Value::Object(counts) +} + +fn object<'a>(value: &'a Value, context: &str) -> Result<&'a Map, String> { + value.as_object().ok_or_else(|| format!("{context} must be an object")) +} + +fn array<'a>(value: &'a Value, name: &str) -> Result, String> { + match value.get(name) { + None | Some(Value::Null) => Ok(Vec::new()), + Some(Value::Array(values)) => Ok(values.iter().collect()), + Some(_) => Err(format!("{name} must be an array")), + } +} + +fn object_array<'a>( + object: &'a Map, + name: &str, +) -> Result, String> { + match object.get(name) { + None | Some(Value::Null) => Ok(Vec::new()), + Some(Value::Array(values)) => Ok(values.iter().collect()), + Some(_) => Err(format!("{name} must be an array")), + } +} + +fn required_string<'a>(object: &'a Map, name: &str) -> Result<&'a str, String> { + optional_string(object, name).filter(|value| !value.is_empty()) + .ok_or_else(|| format!("{name} is required")) +} + +fn optional_string<'a>(object: &'a Map, name: &str) -> Option<&'a str> { + object.get(name).and_then(Value::as_str) +} + +fn required_number(object: &Map, name: &str) -> Result { + optional_number(object, name).ok_or_else(|| format!("{name} must be a number")) +} + +fn optional_number(object: &Map, name: &str) -> Option { + object.get(name).and_then(Value::as_f64) +} + +fn required_u32(object: &Map, name: &str) -> Result { + optional_u32(object, name).ok_or_else(|| format!("{name} must be a positive integer")) +} + +fn optional_u32(object: &Map, name: &str) -> Option { + object.get(name).and_then(Value::as_u64).and_then(|value| u32::try_from(value).ok()) +} + +fn optional_u16(object: &Map, name: &str) -> Option { + object.get(name).and_then(Value::as_u64).and_then(|value| u16::try_from(value).ok()) +} + +fn optional_bool(object: &Map, name: &str) -> Option { + object.get(name).and_then(Value::as_bool) +} + +fn required_path<'a>(path: Option<&'a str>, message: &str) -> Result<&'a str, String> { + path.filter(|value| !value.is_empty()).ok_or_else(|| message.to_string()) +} + +fn create_parent(path: &str) -> Result<(), String> { + let parent = Path::new(path).parent().unwrap_or_else(|| Path::new(".")); + fs::create_dir_all(parent).map_err(|error| format!("create output directory: {error}")) +} + +fn parse_cell(value: &str) -> Result<(u32, u16), String> { + let split = value.find(|character: char| character.is_ascii_digit()) + .ok_or_else(|| format!("invalid cell reference {value:?}"))?; + let (column, row) = value.split_at(split); + if column.is_empty() || row.is_empty() || !column.chars().all(|character| character.is_ascii_alphabetic()) { + return Err(format!("invalid cell reference {value:?}")); + } + let row = row.parse::().map_err(|_| format!("invalid cell reference {value:?}"))? + .checked_sub(1).ok_or_else(|| format!("invalid cell reference {value:?}"))?; + Ok((row, parse_column(column)?)) +} + +fn parse_column(value: &str) -> Result { + if value.is_empty() || !value.chars().all(|character| character.is_ascii_alphabetic()) { + return Err(format!("invalid column {value:?}")); + } + let mut result = 0u32; + for character in value.bytes() { + result = result.checked_mul(26).and_then(|current| current.checked_add(u32::from(character.to_ascii_uppercase() - b'A' + 1))) + .ok_or_else(|| format!("invalid column {value:?}"))?; + } + u16::try_from(result.checked_sub(1).ok_or_else(|| format!("invalid column {value:?}"))?) + .map_err(|_| format!("column out of range {value:?}")) +} + +fn parse_range(value: &str) -> Result<(u32, u16, u32, u16), String> { + let (start, end) = value.split_once(':').ok_or_else(|| format!("invalid range {value:?}"))?; + let (first_row, first_col) = parse_cell(start)?; + let (last_row, last_col) = parse_cell(end)?; + if first_row > last_row || first_col > last_col { return Err(format!("invalid range {value:?}")); } + Ok((first_row, first_col, last_row, last_col)) +} + +fn cell_name(row: u32, col: u16) -> String { + let mut column = u32::from(col) + 1; + let mut letters = String::new(); + while column > 0 { + let remainder = (column - 1) % 26; + letters.insert(0, char::from(b'A' + u8::try_from(remainder).unwrap_or(0))); + column = (column - 1) / 26; + } + format!("{}{}", letters, row + 1) +} + +fn border_style(value: &str) -> Result { + match value { + "" | "none" => Ok(BorderStyle::None), + "thin" => Ok(BorderStyle::Thin), + "medium" => Ok(BorderStyle::Medium), + "thick" => Ok(BorderStyle::Thick), + "dashed" => Ok(BorderStyle::Dashed), + "dotted" => Ok(BorderStyle::Dotted), + "double" => Ok(BorderStyle::Double), + _ => Err(format!("unsupported border style {value:?}")), + } +} + +fn horizontal_alignment(value: &str) -> Result { + match value { + "" | "general" | "left" => Ok(Align::Left), + "center" => Ok(Align::Center), + "right" => Ok(Align::Right), + "fill" => Ok(Align::Fill), + "justify" => Ok(Align::Justify), + _ => Err(format!("unsupported horizontal alignment {value:?}")), + } +} + +fn vertical_alignment(value: &str) -> Result { + match value { + "" | "bottom" => Ok(Align::Bottom), + "top" => Ok(Align::Top), + "center" => Ok(Align::VerticalCenter), + _ => Err(format!("unsupported vertical alignment {value:?}")), + } +} + +fn parse_table_style(value: &str) -> Result { + for (prefix, build) in [ + ("TableStyleLight", TableStyle::Light as fn(u8) -> TableStyle), + ("TableStyleMedium", TableStyle::Medium as fn(u8) -> TableStyle), + ("TableStyleDark", TableStyle::Dark as fn(u8) -> TableStyle), + ] { + if let Some(number) = value.strip_prefix(prefix) { + return number.parse::().map(build).map_err(|_| format!("unsupported table style {value:?}")); + } + } + Err(format!("unsupported table style {value:?}")) +} + +fn parse_chart_type(value: &str) -> Result { + match value { + "area" => Ok(ChartType::Area), + "bar" => Ok(ChartType::Bar), + "col" | "column" => Ok(ChartType::Column), + "line" => Ok(ChartType::Line), + "pie" => Ok(ChartType::Pie), + "doughnut" => Ok(ChartType::Doughnut), + "scatter" => Ok(ChartType::Scatter), + "bubble" => Ok(ChartType::Bubble), + _ => Err(format!("unsupported chart type {value:?}")), + } +} diff --git a/uv.lock b/uv.lock index 4f98766..5c55156 100644 --- a/uv.lock +++ b/uv.lock @@ -33,7 +33,7 @@ name = "appscript" version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "lxml", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "lxml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ca/52/2fa70edfd98f0058219ecc2e365a3ba7aabd42db14ff9d7f44bbdcc5400d/appscript-1.4.0.tar.gz", hash = "sha256:b2c6fc770bf822ea45529c7084bc0ee340e67ab260016b01d28e0449ec8723be", size = 295279, upload-time = "2025-10-08T07:56:39.126Z" } wheels = [ @@ -47,6 +47,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/e3/03dc0f97eab839f72061342d69bd34424e89876ce4026509aab3d74d4f23/appscript-1.4.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:5efce3302c00674b769b79938cc5f66f7791ef45c6419e850a5f1c8f9fcefcc1", size = 85610, upload-time = "2025-10-08T07:56:38.103Z" }, ] +[[package]] +name = "aspose-cells-foss" +version = "26.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "olefile" }, + { name = "pycryptodome" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/38/c4704d0ee0fcddfe69bf1c6b2d1eb8d0c51cebd4cd5e18ac92361f414b49/aspose_cells_foss-26.7.0.tar.gz", hash = "sha256:006dfe6d9dbdbd6d626f3ecc65f800ed838c28e4560178aaaf758482416a7350", size = 292477, upload-time = "2026-07-24T13:53:31.802Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/28/aa193a491df0325a86b99810e4ec4658c50e551eab2cbaad1632074dbddd/aspose_cells_foss-26.7.0-py3-none-any.whl", hash = "sha256:e903641b54ddcbaa1956a6e35e14b90b1d08e96675011f05aafa219d0ef1c720", size = 333188, upload-time = "2026-07-24T13:53:29.97Z" }, +] + [[package]] name = "babel" version = "2.18.0" @@ -362,6 +375,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + [[package]] name = "et-xmlfile" version = "2.0.0" @@ -398,6 +420,9 @@ dependencies = [ ] [package.optional-dependencies] +aspose = [ + { name = "aspose-cells-foss" }, +] dev = [ { name = "mypy" }, { name = "pytest" }, @@ -415,6 +440,7 @@ rust = [ [package.metadata] requires-dist = [ + { name = "aspose-cells-foss", marker = "extra == 'aspose'", specifier = ">=26.7" }, { name = "fastexcel", specifier = ">=0.7.0" }, { name = "matplotlib", specifier = ">=3.7.0" }, { name = "mkdocs-material", marker = "extra == 'docs'", specifier = ">=9.5" }, @@ -443,7 +469,7 @@ requires-dist = [ { name = "xlwings", specifier = ">=0.30.0" }, { name = "xlwt", specifier = ">=1.3.0" }, ] -provides-extras = ["dev", "rust", "docs"] +provides-extras = ["dev", "rust", "docs", "aspose"] [[package]] name = "fastexcel" @@ -1146,6 +1172,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, ] +[[package]] +name = "olefile" +version = "0.47" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/1b/077b508e3e500e1629d366249c3ccb32f95e50258b231705c09e3c7a4366/olefile-0.47.zip", hash = "sha256:599383381a0bf3dfbd932ca0ca6515acd174ed48870cbf7fee123d698c192c1c", size = 112240, upload-time = "2023-12-01T16:22:53.025Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/d3/b64c356a907242d719fc668b71befd73324e47ab46c8ebbbede252c154b2/olefile-0.47-py2.py3-none-any.whl", hash = "sha256:543c7da2a7adadf21214938bb79c83ea12b473a4b6ee4ad4bf854e7715e13d1f", size = 114565, upload-time = "2023-12-01T16:22:51.518Z" }, +] + [[package]] name = "openpyxl" version = "3.1.5" @@ -1405,6 +1440,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, ] +[[package]] +name = "pycryptodome" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, + { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, + { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, + { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, + { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, + { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, + { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, + { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, + { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, + { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, + { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, + { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -2051,19 +2116,39 @@ wheels = [ [[package]] name = "wolfxl" -version = "0.1.0" +version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/df/775d22632067cfeb408a1621930e5b3a8adff8b6497cd780b9565b8bc4a4/wolfxl-0.1.0.tar.gz", hash = "sha256:24bafc7891161b036bd2482b5c30d1b46607155f45b0cdadecd0cb821d9959dc", size = 101351, upload-time = "2026-02-16T06:56:58.838Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/98/477238e547f18f2a221ed7ac496d84a5565b4d406a808a950be297a18f84/wolfxl-0.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3eda40a4214e89b5bdd6cb79a9b1ef7535f562d9ae7e04b8c2e12eb557bdee7", size = 1704813, upload-time = "2026-02-16T06:56:41.036Z" }, - { url = "https://files.pythonhosted.org/packages/52/df/02bbbe841ceea7af0d50ef709d4f72bed91800799bcf0036bbda53092391/wolfxl-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1253d276e069210de7341956c58ef7f2bd021d336f01f94ef86ab01e06ff7c1", size = 1755972, upload-time = "2026-02-16T06:56:43.045Z" }, - { url = "https://files.pythonhosted.org/packages/d3/9c/1214cca9b121ee7ca491fb40cbed4e93e220c734e661d854f77be3521786/wolfxl-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab24eb6d732be42ded39d09ce8ef24feeff5a86730c56c652a1d25d245261fc6", size = 1662399, upload-time = "2026-02-16T06:56:44.991Z" }, - { url = "https://files.pythonhosted.org/packages/b2/44/b2ffb8b4c32ab9ce952f0dbc36b41cf187acde9fe42687e597f33e381128/wolfxl-0.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0af64fc84b2cc68463f646f3785d1caa00c9b92497d19e0a425110255a6f07ab", size = 1598530, upload-time = "2026-02-16T06:56:46.801Z" }, - { url = "https://files.pythonhosted.org/packages/64/2c/cf0a39ec9e15229fc0b3486ebcef81cd71c71321d0c8c63e7924006d34e8/wolfxl-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c51a55c1302d11291f918482c7995a1ad3a572daece73cbefb1e40e6aa902c8", size = 1705644, upload-time = "2026-02-16T06:56:48.408Z" }, - { url = "https://files.pythonhosted.org/packages/18/ca/1fa161476bc9d599515357e64a911c519533947b40248d3109229f9379d5/wolfxl-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16c93dcae0664ecc8a655917d392c241892754a2557d12d493e14c4306e6f45", size = 1757542, upload-time = "2026-02-16T06:56:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/0e/e0/01ba17ee89bf0fec763d1869112a29a37127953bb3abef07e4588c8b989c/wolfxl-0.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d90fc4c57a92171c9081cad4ec3490dd25ed53d9d63bb2f00fac94a34cb5ab03", size = 1507448, upload-time = "2026-02-16T06:56:51.211Z" }, - { url = "https://files.pythonhosted.org/packages/86/02/0b9999e1ce359a95f4a7bf76a1409e412a94f6dee82930820981375a179b/wolfxl-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ac8a6828ecc6cb5e8fcb9ee5d2596820da43dbaa382df5d95677dc18f2b7f20", size = 1704901, upload-time = "2026-02-16T06:56:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/02/bb/ead2bc97276eb7c4c9b2e718c8f91b0dbb27131ecfc42c93bf3e2f259bba/wolfxl-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ac1e7b592bfb223b5bc198d2eac1d3dcb6b5d3181c8be189efaea9c8299f45", size = 1756705, upload-time = "2026-02-16T06:56:54.732Z" }, +dependencies = [ + { name = "defusedxml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/ac/65759994e89287f651a9b5ba599e063e39d7db56b5fcbe709a0937b564f3/wolfxl-2.0.1.tar.gz", hash = "sha256:57d93932457efb0dde3971fdf796a1bec8c6014dc060638459e50e4d7736db13", size = 10530974, upload-time = "2026-08-18T07:30:52.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/28/cccc32d0a397621f8556938f02db97fea9eed47cbb6ace5879a7d2fc88e6/wolfxl-2.0.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a44a23217f3df45bf7817eba97be5cc190d03718aec0b955b9e30356bd59bcb5", size = 3327589, upload-time = "2026-08-18T07:30:03.937Z" }, + { url = "https://files.pythonhosted.org/packages/e0/89/7a89b3e6b2ea642eec0aff3b4e58c214e580d2580fb2e301b7819346a7b3/wolfxl-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d3da48a1b7ec2f1f7b62d2c0d92100bac37e197aace3c9635ab137a56a8e3ae", size = 3153645, upload-time = "2026-08-18T07:30:05.454Z" }, + { url = "https://files.pythonhosted.org/packages/81/bc/798df1baa83600aefdd8651ca36db0079456489050987889c734e7e56371/wolfxl-2.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:ec77009031fb34c7802278cbc5ca5cd95f79f9b29a9da89ca41b8b509b9d3d87", size = 3232132, upload-time = "2026-08-18T07:30:07.079Z" }, + { url = "https://files.pythonhosted.org/packages/56/c4/5e03becc03814e56d8a765ee51f4a0aeb87c68333c4d9c03bc3ba16774b6/wolfxl-2.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6996b9e0d94ba25ed07e5a968227005fe5ef418c6c42060093a615d1fe72e309", size = 3364313, upload-time = "2026-08-18T07:30:08.602Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9d/192ff24dd4e035d60a039eaf9af732851174057b430dd731457100bbf7c7/wolfxl-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:717126da60bf77b41b6fe1f2302fbedb9e3543fee5a951beef2a8d07e9f48b43", size = 3374507, upload-time = "2026-08-18T07:30:10.25Z" }, + { url = "https://files.pythonhosted.org/packages/79/c6/9f85c6d0c6f928d694ad2048c81faa394feefc05f0c2979cfc640612d404/wolfxl-2.0.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9461100bc0e979aa1e19b29e405914245221e591ba8628d26ad5b3f1fa38a542", size = 3323795, upload-time = "2026-08-18T07:30:12.026Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/faa95ecefd9d085b4ea1cfcb1ca1c4f3de20603a1da797c62f7d83fd11a3/wolfxl-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d08f2e23e151b9ef51a84cde8bf55f52fa7ad8c67c15b5d1d3c2c713aafa07ae", size = 3151192, upload-time = "2026-08-18T07:30:13.649Z" }, + { url = "https://files.pythonhosted.org/packages/3b/65/6f424e6fadd072ed60c8d644e1c785205e4616e5ab189751500b4aa8e5eb/wolfxl-2.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:128b7a15037a3072b9657a7333f2d5aad18a7aa3e6643856870fc34e42d7632e", size = 3230920, upload-time = "2026-08-18T07:30:15.318Z" }, + { url = "https://files.pythonhosted.org/packages/26/52/a24e280a72561b694b107946bfe3371602dc3e7761542412954ee9dfdab1/wolfxl-2.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:85437f13b5fcb1e4fce5c5c3d21f71db3c18685efd10bcd61be24a1363917f53", size = 3366381, upload-time = "2026-08-18T07:30:17.194Z" }, + { url = "https://files.pythonhosted.org/packages/82/46/8cc977e25c4570494fe0fb436d81f1b6061d729f5f14d6eebe49dfb82e2f/wolfxl-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:807d89a4f73f069322e27750f02ee428d27b955ae471a7e420643e612040cf89", size = 3365195, upload-time = "2026-08-18T07:30:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/a5/19/be4cef90586d77b25f85f8e5a5db7aa7743091feea8be0b22fe78fc625cc/wolfxl-2.0.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9092422063ceb1291b958716ad796a37b2df69d19c694fcc57923f44874b3403", size = 3324502, upload-time = "2026-08-18T07:30:20.024Z" }, + { url = "https://files.pythonhosted.org/packages/e7/06/fa126fd43d458ecd83294130ba9a91fa345c7cd35a1f52a7543cd1e10c74/wolfxl-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be728fa4e04804a2c365a6cac4950fb7be010a26db44da39cabc504b32c27228", size = 3151284, upload-time = "2026-08-18T07:30:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/85/1a/d129b7d9881c200104eef501b4c0cdb8a44ca53160e2855803c9da3c67fa/wolfxl-2.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:1763e329d994ac0309e1552bf5b19fa9377474130567691a9d4b957b49f51226", size = 3230311, upload-time = "2026-08-18T07:30:22.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/80/1493b3d0e670ccc27a9a82de593e18ba8a8856d09db094fbf27459111c04/wolfxl-2.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a2f790b2dcf8de66f063d3197827c86fcb57f3817a9408d7c1977b9d4745147c", size = 3365113, upload-time = "2026-08-18T07:30:24.464Z" }, + { url = "https://files.pythonhosted.org/packages/ea/17/f7096c60f62fc4d580facbd8cfcf35ed97ce38b04563166d3d54c1199efb/wolfxl-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:aa079bce1ea79d94bbb6b26cbced8a547449d7801d898d46d35a9eaa66378726", size = 3364744, upload-time = "2026-08-18T07:30:25.991Z" }, + { url = "https://files.pythonhosted.org/packages/e0/2e/6cb9ec837327433ddd2c9b9630127accf5656b70ae64d2bb41d96d06700a/wolfxl-2.0.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:dbfde5bfc0450e2455099fcd8eadd80a2260ad378c6f8a98b4fcf33fc12e4d8a", size = 3323781, upload-time = "2026-08-18T07:30:27.373Z" }, + { url = "https://files.pythonhosted.org/packages/14/21/6348295559e4a8e77b27f9f4aecb4838b64fc1b186e5149df08247ad8021/wolfxl-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9fd37dddf9c765673533f8afd8a974a737f24d4fd7f9b6c23e05e1d66e989782", size = 3152454, upload-time = "2026-08-18T07:30:28.788Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e5/a37e045e01d30e5ccf90c752b08ede0d5b704dda6eef4bbc0700bc45df43/wolfxl-2.0.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:45007ed29f6dee8ad92bdf9f196efe3c9981ac6ddc54c5176e07de433c98f18f", size = 3231819, upload-time = "2026-08-18T07:30:30.224Z" }, + { url = "https://files.pythonhosted.org/packages/17/a9/b9f7320226704d2929ff219c71abe417703c743b6e74037592df6e860f0b/wolfxl-2.0.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:9ce3124f7db927537fff0d8e61d362cc94313b8285702fbd7203f80a90e6518a", size = 3365061, upload-time = "2026-08-18T07:30:31.63Z" }, + { url = "https://files.pythonhosted.org/packages/70/c9/ca0c1d76b3387dd3e8708ecba63a974bfd3c255f7eaf42108ac37c326df7/wolfxl-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:069e1be537b44bf9d003c8fefa721537b1a5478232ec4248378319005aaeff69", size = 3365582, upload-time = "2026-08-18T07:30:33.241Z" }, + { url = "https://files.pythonhosted.org/packages/95/ac/2d95abaa2c00f865fdf60f837db827c011c18fa2cdcc4e2138954d2f2595/wolfxl-2.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3dc52a0ee9341b20e14f72f57e4e01e44887c1aad43a122380f4cce89739fab0", size = 3236416, upload-time = "2026-08-18T07:30:34.84Z" }, + { url = "https://files.pythonhosted.org/packages/f7/44/5c0e799b855da4f55553e61741fa44b89ed1da489a9bd29fa3fe6dba9ef5/wolfxl-2.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:41fb6ac734d80cbadf904be79ed3e23513a66422dd24026306eb2b6aba63ce40", size = 3375950, upload-time = "2026-08-18T07:30:36.245Z" }, + { url = "https://files.pythonhosted.org/packages/45/ed/81f4fdf0df823af92fdbd512ae52a653b2b56209c7647f7acb4b217c147f/wolfxl-2.0.1-cp315-cp315-manylinux_2_28_x86_64.whl", hash = "sha256:64cf32215c985c13002752939009509ba1b4164904a5bdd7efc39992e7df9904", size = 3365063, upload-time = "2026-08-18T07:30:38.301Z" }, + { url = "https://files.pythonhosted.org/packages/2b/26/7ed7d4aec18e23353957b2237bc5e78e06230fc19dd59a519731b0350e7b/wolfxl-2.0.1-cp315-cp315t-manylinux_2_28_x86_64.whl", hash = "sha256:41daab6e511ec253d0f4a87ffb8d961d9b7fc2e2dde56c2b08633b745be567b9", size = 3375953, upload-time = "2026-08-18T07:30:39.9Z" }, + { url = "https://files.pythonhosted.org/packages/8a/90/de6c1919a57c72125b99332fdad3ded2666600ea6c0a40367a1b845c8d12/wolfxl-2.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:370ff2cfa41158a4a0979ca07843241c4a9805f42d9c1f1dae6463358716edb6", size = 3235719, upload-time = "2026-08-18T07:30:48.673Z" }, + { url = "https://files.pythonhosted.org/packages/37/21/79f1e3d0b6bda50b98e417e7b34a98dfcfd29b1720af85dc9eadb632f7f8/wolfxl-2.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:07bab6fd6baa29068039c1d87b519f3772ba1a1a3057e95195944051ff11e2bb", size = 3366936, upload-time = "2026-08-18T07:30:50.067Z" }, ] [[package]]