diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..47d64ac --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,2 @@ +# remote-source-sync receipt: "source_key" is the public git commit sha, not a credential +results-2026-10-02/perf/README.md:generic-api-key:36 diff --git a/METHODOLOGY.md b/METHODOLOGY.md index 82fcccc..771230f 100644 --- a/METHODOLOGY.md +++ b/METHODOLOGY.md @@ -102,12 +102,27 @@ 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. +- **Preservation (content model)**: the template is read into the vendored + xlsx content model (`src/excelbench/harness/content_model_xlsx.py`, copied + verbatim from `officelibs-corpus`), the two declared cell edits are applied + to that model the way a correct engine applies them, and the result is + compared with the output's model. Any difference is an unexpected change, + counted per feature (`features_changed`); `feature_preservation` is `k/n` + for the `n` features present in the template. Custom XML data items are an + extra scorer-side feature (`custom_xml`, canonical XML plus datastore id). + Cached results of formula cells are recalculation state and are not + compared; formula text is. +- **Edits applied**: each edited cell must hold its new value, checked + separately from preservation. +- **Integrity**: dangling relationships and parts without a content type are + reported but not scored. +- **Verdict**: Preserved / Changed `` / Edits missing / Failed. + +Part names, relationship ids, XML serialization and document metadata are not +content, so an equivalent re-serialization scores the same as a byte copy. +Part-name based checks (lost/added parts, worksheet elements in same-named +parts) survive only as an unscored `diagnostics` block. Cite wall time and +preservation together. ## Calculation Lane diff --git a/README.md b/README.md index 91215bd..829490b 100644 --- a/README.md +++ b/README.md @@ -13,24 +13,41 @@ cross-language context lane (Apache POI, Excelize, zavora-xlsx). Tier 4 ## 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) +> Competitor snapshot: 2026-10-02 | WolfXL 2.0.5 (latest PyPI) | 17 fidelity adapters incl. SheetJS CE 0.20.3, ExcelJS 4.4.0, LibreOffice 26.8.0.3 | [Snapshot README](results-2026-10-02/README.md) | [Fidelity](results-2026-10-02/xlsx/README.md) | [Mutation](results-2026-10-02/mutation/README.md) | [Calc](results-2026-10-02/calc/README.md) | [Cross-language](results-2026-10-02/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). +> Green features in that snapshot (read / write, out of 21¹): openpyxl +> 21/21 / 21/21, WolfXL 19/21 / 18/21, ExcelJS 12/21 / 15/21, +> aspose-cells-foss 11/21 / 14/21, LibreOffice 12/21 / 12/21, SheetJS CE +> 9/21 / 8/21; write-only xlsxwriter 15/21. > -> 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%). +> Mutation suite (two-cell edit on a corporate template, content-model +> preservation; features kept / features in the template): WolfXL +> Preserved 17/17; openpyxl 16/17 (drops custom XML); LibreOffice 15/17 +> (cell styles, page setup); aspose-cells-foss 15/17 (drops 87 string +> cells, custom XML); SheetJS 8/17 and zavora-xlsx 8/17 (charts, tables, +> styles and more); ExcelJS fails to load the template. Every engine that +> ran applied both edits. Wall times in that run are not comparable (host +> under heavy unrelated load). > > 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. +> oracle): LibreOffice 133/133, aspose-cells-foss 25/133, WolfXL 0/133, +> zavora 0/133. SheetJS CE, ExcelJS, and the other non-calculating +> adapters are not applicable. +> +> Cross-language context (write lane): Apache POI 5.5.1 18/21, Excelize +> 2.10.1 18/21, zavora-xlsx 0.1.2 8/21. The POI and Excelize misses are +> the three Tier 4 features, which the ExcelBench adapters do not +> implement yet (`NotImplementedError`). They are not library gaps. +> +> ¹ `pivot_tables` is excluded from every denominator because no adapter +> produced a score for it in either competitor snapshot. > > 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. > +> Performance snapshot: 2026-10-02 UTC | WolfXL 2.0.5 through its public API (`wolfxl.load_workbook`, `wolfxl.Workbook`) | [Perf](results-2026-10-02/perf/README.md). It supersedes the 2026-04-29 perf numbers for WolfXL, which measured private backend objects. +> > Cross-language context snapshot: [Apache POI `18/18`](results-cross-language/README.md) | [Excelize `18/18`](results-cross-language/README.md) > > 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. @@ -71,7 +88,7 @@ Use this when the question is: how does WolfXL compare to serious spreadsheet to 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? +Use this when the question is: which engine can surgically edit a corporate template fastest while preserving everything else in the workbook? 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)? @@ -80,26 +97,26 @@ Use this when the question is: which engine actually computes a 133-formula fina | Library | Caps | Fidelity | Read Speed | Write Speed | Modify | |---------|:----:|:--------:|:----------:|:-----------:|:------:| -| **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 | -| pandas | R+W | 3/18 in 2026-04-29 release snapshot | <1x | <1x | Rebuild | -| polars | R | 0/18 in 2026-04-29 release snapshot | ~1x | -- | No | +| **wolfxl** | R+W | R 20/21, W 19/21 in 2026-09-08 competitor snapshot (18/18 in 2026-04-29 snapshot) | 1.69x (13.46 ms) | 1.20x (22.28 ms) | Patch (Preserved, 17/17 features in 2026-10-02 mutation suite) | +| openpyxl | R+W | R 21/21, W 21/21 in 2026-09-08 competitor snapshot | 1.00x (22.79 ms, baseline) | 1.00x (26.70 ms, baseline) | Rewrite (16/17 features in 2026-10-02 mutation suite) | +| aspose-cells-foss | R+W | R 11/21, W 14/21 in 2026-09-08 competitor snapshot | not measured | not measured | Rewrite (15/17 features) | +| xlsxwriter | W | 15/18 in 2026-04-29 release snapshot | -- | 0.86x (31.12 ms) | No | +| xlsxwriter-constmem | W | 12/18 in 2026-04-29 release snapshot | -- | 0.86x (31.17 ms) | No | +| python-calamine | R | 1/18 in 2026-04-29 release snapshot | 14.02x (1.63 ms) | -- | No | +| pandas | R+W | 3/18 in 2026-04-29 release snapshot | 0.80x (28.43 ms) | 1.00x (26.66 ms) | Rebuild | +| polars | R | 0/18 in 2026-04-29 release snapshot | 3.72x (6.13 ms) | -- | No | -> 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). +> Speed columns come from the [2026-10-02 perf snapshot](results-2026-10-02/perf/README.md): sum of per-feature p50 wall times over the same 19 xlsx features for every library (warmup 3, 25 iterations, Apple M4 Pro, Python 3.12.3), shown as openpyxl's total divided by the library's total. WolfXL 2.0.5 is measured through its public API (`wolfxl.load_workbook`, `wolfxl.Workbook`), like every other library. aspose-cells-foss was not part of the perf run. Always cite the artifact date, workload, and profile. See [METHODOLOGY.md](METHODOLOGY.md) and [Public Reporting Status](docs/public-reporting.md). ### Key Findings -- **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 +- **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 (21 scored features; `pivot_tables` unscored), openpyxl holds 21/21 read and write while WolfXL 2.1.0 reaches 20/21 read and 19/21 write - **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 +- **Patch modify is structurally different**: WolfXL's `load_workbook(path, modify=True)` uses surgical ZIP patching; it is the only engine whose output keeps every template feature in the 2026-10-02 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**: `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 +- **Calculation is a differentiator**: only LibreOffice computes the full 133-formula DAG (2026-10-02 snapshot); aspose-cells-foss covers 25/133; WolfXL 2.0.5 scores 0/133 because `Workbook.calculate()` runs but the saved workbook carries no cached formula values 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. @@ -119,9 +136,9 @@ See the [release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md) fo | Library | Version | Lang | Caps | Green Features | |:--------|:--------|:-----|:-----|:--------------:| -| [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) | +| [WolfXL](https://github.com/SynthGL/wolfxl) | 2.1.0 | Python (Rust core) | R+W | R 20/21, W 19/21 (2026-09-08 snapshot) | +| [openpyxl](https://openpyxl.readthedocs.io/) | 3.1.5 | Python | R+W | R 21/21, W 21/21 (2026-09-08 snapshot) | +| [aspose-cells-foss](https://pypi.org/project/aspose-cells-foss/) | 26.7 | Python (JVM-core FOSS) | R+W | R 11/21, W 14/21 (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 | @@ -135,8 +152,9 @@ See the [release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md) fo | [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. +> 2026-04-29 release snapshot and `x/21` from the 2026-09-08 competitor +> snapshot (Tier 4 added; `pivot_tables` is unscored and excluded from the +> denominator). Never mix counts across snapshots. ### Cross-Language Context (oracle helpers) @@ -289,7 +307,7 @@ uv run excelbench generate --output fixtures/excel | **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. -> Green-feature denominators: /18 in the 2026-04-29 release snapshot, /22 in the 2026-09-08 competitor snapshot. +> Green-feature denominators: /18 in the 2026-04-29 release snapshot, /21 in the 2026-09-08 and 2026-10-02 competitor snapshots (22 features modeled; `pivot_tables` is unscored and excluded). ### Planned @@ -305,8 +323,9 @@ None currently queued. Tier 4 (charts anchoring, print settings, protection) shi - **[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 -- **[Performance results](results/perf/README.md)** -- throughput benchmarks (cells/s) -- **[Release snapshot perf](results-release-2026-04-28/perf/README.md)** -- matching wheel-backed perf snapshot +- **[Performance results](results/perf/README.md)** -- 2026-04-20 perf snapshot (historical; its WolfXL column measured private backend objects) +- **[Release snapshot perf](results-release-2026-04-28/perf/README.md)** -- 2026-04-29 perf snapshot (historical; its WolfXL column measured private backend objects) +- **[2026-10-02 perf snapshot](results-2026-10-02/perf/README.md)** -- current perf: 13 Python adapters, 19 features, WolfXL 2.0.5 through its public API - **[Dashboard](results/DASHBOARD.md)** -- combined fidelity + performance comparison - **[Release snapshot dashboard](results-release-2026-04-28/DASHBOARD.md)** -- combined view for the fresh rerun - **[Heatmap (PNG)](results/xlsx/heatmap.png)** | **[SVG](results/xlsx/heatmap.svg)** -- visual score matrix diff --git a/docs-site/adapters/openpyxl.mdx b/docs-site/adapters/openpyxl.mdx index 5f49993..2019597 100644 --- a/docs-site/adapters/openpyxl.mdx +++ b/docs-site/adapters/openpyxl.mdx @@ -53,4 +53,4 @@ wb = load_workbook("data.xlsx", read_only=True) openpyxl is **slow** by default. For large files: - Use `read_only=True` for reading (no in-memory model built) -- Consider WolfXL for 4-6x read speedup with comparable fidelity +- Consider WolfXL for a 1.69x read speedup (2026-10-02 perf snapshot: WolfXL 2.0.5 `wolfxl.load_workbook` 13.46 ms vs openpyxl 22.79 ms, summed p50 over 19 features); in the 2026-10-02 fidelity snapshot WolfXL has 17/21 features green in both read and write against openpyxl's 21/21 diff --git a/docs-site/adapters/overview.mdx b/docs-site/adapters/overview.mdx index 1cadaed..061274c 100644 --- a/docs-site/adapters/overview.mdx +++ b/docs-site/adapters/overview.mdx @@ -33,7 +33,7 @@ ExcelBench tests adapters across three categories. | Adapter | Capabilities | Notes | |---------|-------------|-------| -| `wolfxl` | R+W+Modify | WolfXL: calamine read + rust_xlsxwriter write + XlsxPatcher | +| `wolfxl` | R+W+Modify | WolfXL public API: `load_workbook`, `Workbook`, patch-mode `load_workbook(path, modify=True)` | | `calamine-styled` | R | calamine fork with style support | | `rust-calamine` | R | Basic calamine (no styles) | | `rust-xlsxwriter` | W | rust_xlsxwriter write bindings | diff --git a/docs-site/adapters/wolfxl.mdx b/docs-site/adapters/wolfxl.mdx index 01e1a17..3f4b252 100644 --- a/docs-site/adapters/wolfxl.mdx +++ b/docs-site/adapters/wolfxl.mdx @@ -1,15 +1,17 @@ --- title: "WolfXL" -description: "The fastest Python-accessible Excel library. Read + Write + Modify in one." +description: "Rust-backed Python Excel library with an openpyxl-compatible API. Read + Write + Modify in one." --- -WolfXL is a hybrid Rust library that combines three backends: +WolfXL is a Rust-backed Python library with an openpyxl-compatible API. ExcelBench drives it through that public API: -| Operation | Backend | Speed vs openpyxl | -|-----------|---------|-------------------| -| Read | calamine (styled fork) | **4-6x faster** | -| Write | rust_xlsxwriter | **5x faster** | -| Modify | XlsxPatcher (ZIP surgery) | **10-14x faster** | +| Operation | Public API (WolfXL 2.0.5) | Speed vs openpyxl (2026-10-02 perf snapshot) | +|-----------|---------------------------|-------------------| +| Read | `wolfxl.load_workbook(path)` | **1.69x faster** (13.46 ms vs 22.79 ms) | +| Write | `wolfxl.Workbook()` then `save(path)` | **1.20x faster** (22.28 ms vs 26.70 ms) | +| Modify | `wolfxl.load_workbook(path, modify=True)` then `save(path)`: patch mode rewrites only the changed sheet XML and copies every other ZIP entry unchanged | No current measurement | + +Speed figures are sums of per-feature p50 wall times over the same 19 xlsx features for both libraries (warmup 3, 25 iterations, Apple M4 Pro, Python 3.12.3), measured on WolfXL 2.0.5 through its public API (`wolfxl.load_workbook`, `wolfxl.Workbook`). Source: `results-2026-10-02/perf/README.md`. ## Install @@ -35,7 +37,7 @@ ws = wb.active ws["A1"] = "Hello, world" wb.save("output.xlsx") -# Modify (surgical patch — no full rewrite) +# Modify (surgical patch, no full rewrite) wb = wolfxl.load_workbook("template.xlsx", modify=True) ws = wb.active ws["B2"] = 42 @@ -46,21 +48,21 @@ wb.save("patched.xlsx") Standard Excel libraries rewrite the entire `.xlsx` ZIP archive on save. WolfXL's modify mode instead patches only the changed XML sheets in-place, leaving all other ZIP entries untouched. -This is 10-14x faster for templates with large static content (images, charts, pivot tables) where only a few cells change. +Large static content in a template (images, charts, pivot tables) is never parsed or re-serialized when only a few cells change. ## Benchmark Scores -From the current ExcelBench run: +From the 2026-10-02 snapshot (WolfXL 2.0.5; fidelity from `results-2026-10-02/xlsx`, 21 scored features with `pivot_tables` unscored; speed from `results-2026-10-02/perf`): | Axis | Score | |------|-------| -| Fidelity | 87.5% (14/16 features = 3) | -| Read Speed | 100 (5.9x openpyxl, capped) | -| Write Speed | 100 (3.7x openpyxl, capped) | -| Feature Coverage | 88.2% | +| Fidelity | 17/21 features green in both read and write (read 19/21, write 18/21) | +| Read Speed | 1.69x openpyxl (WolfXL 2.0.5 public API) | +| Write Speed | 1.20x openpyxl (WolfXL 2.0.5 public API) | +| Feature Coverage | 100% (21/21 features score at least 1 in read or write) | | Capability Breadth | 100 (R+W+Modify) | -Known gaps: `alignment` (indent level) = 1/3, `images` (read) = 0/3. +Known gaps: `named_ranges` read 2/3 and write 2/3, `tables` read 2/3, `page_setup` write 2/3, `chart_anchor` write 0/3. ## Source diff --git a/docs-site/cli/perf.mdx b/docs-site/cli/perf.mdx index 33a341d..7074fd2 100644 --- a/docs-site/cli/perf.mdx +++ b/docs-site/cli/perf.mdx @@ -29,7 +29,7 @@ For each library, the perf runner captures: - **Bulk read** — `read_sheet_values()` returning all cells at once (10K cells) - **Bulk write** — `write_sheet_values()` writing all cells at once (100K cells) -Rust adapters (WolfXL, calamine-styled) implement bulk methods for maximum throughput. +Bulk workloads run only on adapters that implement `read_sheet_values()` or `write_sheet_values()`; for other adapters the harness records the bulk operation as failed. The WolfXL adapter implements both through WolfXL's public worksheet API, not a separate bulk path. ### Options @@ -48,13 +48,13 @@ uv run excelbench perf --tests fixtures/excel --output results ### Reference Numbers -All on Apple M-series, release build: +From the 2026-10-02 perf snapshot (`results-2026-10-02/perf/README.md`): Apple M4 Pro, Python 3.12.3, warmup 3, 25 iterations, the same 19 xlsx features for every library. Totals are sums of per-feature p50 wall times; the multiple is openpyxl's total divided by the library's total. -| Library | Bulk Read (ops/s) | Bulk Write (ops/s) | -|---------|-------------------|--------------------| -| WolfXL | ~1.26M | ~1.73M | -| openpyxl | ~372K | ~347K | -| python-calamine | ~1.1M | — | -| pandas | ~630K | ~660K | +| Library | Read p50 total | Read vs openpyxl | Write p50 total | Write vs openpyxl | +|---------|----------------|------------------|-----------------|-------------------| +| WolfXL 2.0.5 | 13.46 ms | 1.69x | 22.28 ms | 1.20x | +| openpyxl 3.1.5 | 22.79 ms | 1.00x | 26.70 ms | 1.00x | +| python-calamine 0.8.2 | 1.63 ms | 14.02x | n/a (read-only) | n/a | +| pandas 3.0.6 | 28.43 ms | 0.80x | 26.66 ms | 1.00x | -WolfXL is **3-5x faster** than openpyxl across workloads. +WolfXL is measured through its public API (`wolfxl.load_workbook`, `wolfxl.Workbook`), the same kind of surface as every other library. It reads 1.69x and writes 1.20x faster than openpyxl on this workload. diff --git a/docs-site/index.mdx b/docs-site/index.mdx index d75cad3..5848f45 100644 --- a/docs-site/index.mdx +++ b/docs-site/index.mdx @@ -21,7 +21,7 @@ ExcelBench scores Python Excel libraries on two dimensions: - **Fidelity** — does the library correctly read and write Excel features? - **Performance** — how fast is it, and how much memory does it use? -It tests **17 features** across **12+ adapters** using real Excel-generated fixtures as ground truth. Every score is reproducible from a single command. +In the 2026-10-02 snapshot it scores **21 features** (22 fixtures; `pivot_tables` is unscored) across **17 adapters**, using Excel-generated fixtures as ground truth (the three Tier 4 fixtures are openpyxl-structural). Every score is reproducible from a single command. diff --git a/docs/public-reporting.md b/docs/public-reporting.md index 3c080a6..c449209 100644 --- a/docs/public-reporting.md +++ b/docs/public-reporting.md @@ -12,6 +12,7 @@ This page explains what the current ExcelBench repo artifacts mean and how to ci - Fresh WolfXL 2.0 wheel-backed release snapshot: `results-release-2026-04-28/` generated 2026-04-29 UTC - Current checked-in cross-language context snapshot: `results-cross-language/` generated 2026-04-29 UTC - Current checked-in cross-language pivot capability artifact: `results-cross-language-pivots/` generated 2026-04-29 UTC +- Current competitor snapshot: `results-2026-10-02/` (fidelity, mutation, calc, cross-language, perf) generated 2026-10-02 UTC with WolfXL 2.0.5 ## How To Cite ExcelBench Safely @@ -26,15 +27,20 @@ This page explains what the current ExcelBench repo artifacts mean and how to ci |---|---|---| | `results/xlsx/README.md` | 2026-02-17 | Current checked-in public XLSX fidelity snapshot | | `results/DASHBOARD.md` | 2026-02-17 | Current checked-in combined dashboard snapshot | -| `results/perf/README.md` | 2026-04-20 | Newer performance rerun with fresher timing data | +| `results/perf/README.md` | 2026-04-20 | Historical performance snapshot; its WolfXL column measured private backend objects and is superseded by `results-2026-10-02/perf/` | | `results-release-2026-04-28/README.md` | 2026-04-29 | Fresh wheel-backed WolfXL 2.0 fidelity rerun | -| `results-release-2026-04-28/perf/README.md` | 2026-04-29 | Matching wheel-backed performance rerun | +| `results-release-2026-04-28/perf/README.md` | 2026-04-29 | Historical wheel-backed performance rerun; its WolfXL column measured private backend objects and is superseded by `results-2026-10-02/perf/` | | `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 | +| `results-2026-10-02/xlsx/README.md` | 2026-10-02 | Competitor fidelity snapshot: 21 scored features (`pivot_tables` unscored), 17 adapters including sheetjs, exceljs, libreoffice; WolfXL 2.0.5 | +| `results-2026-10-02/mutation/README.md` | 2026-10-02 | Template-mutation lane: preservation is valid; wall time and RSS are not comparable (host under heavy unrelated load) | +| `results-2026-10-02/calc/README.md` | 2026-10-02 | Formula-recalculation tier vs LibreOffice 26.8.0.3 oracle on the cache-free 133-formula fixture | +| `results-2026-10-02/cross-language/README.md` | 2026-10-02 | Cross-language context: Apache POI 5.5.1, Excelize 2.10.1, zavora-xlsx 0.1.2 | +| `results-2026-10-02/perf/README.md` | 2026-10-02 | Performance snapshot: April's 19 features x 13 Python adapters, warmup 3, 25 iterations, WolfXL 2.0.5 through its public API, Apple M4 Pro | ## Safe Claims Right Now diff --git a/pyproject.toml b/pyproject.toml index ad38bfb..6fb9451 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,10 @@ exclude = ["packages"] [tool.ruff.lint] select = ["E", "F", "I", "N", "W", "UP"] +[tool.ruff.format] +# Vendored verbatim (see its header); reformatting would break the recorded sha256. +exclude = ["src/excelbench/harness/content_model_xlsx.py"] + [tool.mypy] python_version = "3.11" strict = true @@ -143,6 +147,11 @@ module = [ ignore_missing_imports = true disable_error_code = ["import-untyped"] +[[tool.mypy.overrides]] +# Vendored verbatim from officelibs-corpus; kept byte-identical to its source. +module = ["excelbench.harness.content_model_xlsx"] +ignore_errors = true + [[tool.mypy.overrides]] module = [ "excelbench.harness.adapters.rust_adapter_utils", diff --git a/results-2026-10-02/README.md b/results-2026-10-02/README.md new file mode 100644 index 0000000..46a774f --- /dev/null +++ b/results-2026-10-02/README.md @@ -0,0 +1,43 @@ +# ExcelBench competitor snapshot 2026-10-02 + +| Lane | Artifacts | Command | +| --- | --- | --- | +| Fidelity (17 adapters) | [xlsx/](xlsx/README.md) | `excelbench benchmark -t fixtures/excel -o results-2026-10-02/xlsx -a openpyxl -a xlsxwriter -a python-calamine -a aspose-cells-foss -a wolfxl -a pylightxl -a xlrd -a pyexcel -a xlwt -a pandas -a xlsxwriter-constmem -a openpyxl-readonly -a polars -a tablib -a sheetjs -a exceljs -a libreoffice` then `excelbench heatmap -i results-2026-10-02/xlsx/results.json -o results-2026-10-02/xlsx` | +| Template mutation | [mutation/](mutation/README.md) | `excelbench mutation -o results-2026-10-02/mutation --repeats 3` | +| Formula recalculation | [calc/](calc/README.md) | `excelbench calc -o results-2026-10-02/calc` | +| Cross-language context | [cross-language/](cross-language/README.md) | `EXCELBENCH_ORACLE_DOCKER_CONTEXT=pc excelbench cross-language-context -t fixtures/excel -o results-2026-10-02/cross-language` | + +## Versions + +| Library | Version | Runtime | +| --- | --- | --- | +| wolfxl | 2.0.5 (latest PyPI release when run) | Python wheel | +| openpyxl / openpyxl-readonly | 3.1.5 | Python | +| aspose-cells-foss | 26.7.0 | Python | +| xlsxwriter / xlsxwriter-constmem | 3.2.9 | Python | +| python-calamine | 0.6.1 | Python | +| pandas | 3.0.0 | Python | +| polars | 1.38.1 | Python | +| pyexcel | 0.7.4 | Python | +| pylightxl | 1.61 | Python | +| tablib | 3.9.0 | Python | +| xlrd | 2.0.2 | Python | +| xlwt | 1.3.0 | Python | +| sheetjs (npm `xlsx`, Community Edition) | 0.20.3 | Node v22.18.0 via `tools/external-oracles/sheetjs` | +| exceljs | 4.4.0 | Node v22.18.0 via `tools/external-oracles/exceljs` | +| libreoffice | 26.8.0.3 (build bce0998afefdbc355585ca324285661a2170ba77) | headless `soffice` + UNO macro via `tools/external-oracles/libreoffice` | +| zavora-xlsx | 0.1.2 | Rust, local `cargo run` (cargo 1.92.0) via `tools/external-oracles/zavora` | +| apache-poi | 5.5.1 | Docker image `excelbench-poi-oracle:5.5.1` (`ef46106ed14d`) on context `pc` (linux/amd64) | +| excelize | 2.10.1 | Docker image `excelbench-excelize-oracle:2.10.1` (`425caf1a873f`) on context `pc` (linux/amd64) | + +## Host + +macOS 26.5.1 (25F80), Apple M5 Pro, 64 GB, arm64; Python 3.13.9; ExcelBench at `b65866c` plus the uncommitted `officelibs-m2` adapter work. +The fidelity and mutation lanes ran while the host carried heavy unrelated load; fidelity scores are unaffected, mutation timings are not comparable (see the mutation README). + +## Lane membership + +- Fidelity: every 2026-09-08 adapter plus `sheetjs`, `exceljs`, `libreoffice`. `pivot_tables` is not scored by any adapter, so green-feature denominators are /21. +- Mutation: every engine that can open and edit an existing workbook (`openpyxl`, `wolfxl`, `aspose-cells-foss`, `zavora-xlsx`, `sheetjs`, `exceljs`, `libreoffice`). +- Calc: engines with a recalculation API; non-calculating adapters are listed as N/A in the calc README. +- Cross-language: `apache-poi`, `excelize`, `zavora-xlsx`. diff --git a/results-2026-10-02/calc/README.md b/results-2026-10-02/calc/README.md new file mode 100644 index 0000000..e354a65 --- /dev/null +++ b/results-2026-10-02/calc/README.md @@ -0,0 +1,36 @@ +# 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 | 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 | + +wolfxl: 133/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) + +## Scope (snapshot runner note) + +The calc tier scores engines that expose a recalculation API. Libraries without +one are **not applicable** here, not scored 0: + +| Adapter | Calc tier | Reason | +| --- | --- | --- | +| openpyxl, openpyxl-readonly, xlsxwriter, xlsxwriter-constmem, pandas, polars, python-calamine, pylightxl, pyexcel, tablib, xlrd, xlwt | N/A | No formula evaluation engine; they read or write cached values / formula text only | +| sheetjs (CE 0.20.3) | N/A | SheetJS Community Edition does not evaluate formulas | +| exceljs 4.4.0 | N/A | ExcelJS stores formulas and cached results but has no calculation engine | +| apache-poi 5.5.1 | Not run | POI ships `FormulaEvaluator`, but the ExcelBench POI helper has no evaluate operation, so there is no harness path to score it yet | +| excelize 2.10.1 | Not run | Excelize ships `CalcCellValue`, but the ExcelBench Excelize helper has no evaluate operation, so there is no harness path to score it yet | + +The `libreoffice` row above is LibreOffice 26.8.0.3 headless recalculation (it is also the oracle that produced `fixtures/calc/expected_values.json`). +`wolfxl` is WolfXL 2.0.5 from PyPI: `Workbook.calculate()` runs, but the saved workbook carries no cached formula values, so every scored cell reads back empty. + +Command: `excelbench calc -o results-2026-10-02/calc` (defaults: `fixtures/calc/financial_model.xlsx`, `fixtures/calc/expected_values.json`). diff --git a/results-2026-10-02/calc/aspose_cells_foss/financial_model.xlsx b/results-2026-10-02/calc/aspose_cells_foss/financial_model.xlsx new file mode 100644 index 0000000..1fdb3b8 Binary files /dev/null and b/results-2026-10-02/calc/aspose_cells_foss/financial_model.xlsx differ diff --git a/results-2026-10-02/calc/libreoffice/financial_model.xlsx b/results-2026-10-02/calc/libreoffice/financial_model.xlsx new file mode 100644 index 0000000..6cdd592 Binary files /dev/null and b/results-2026-10-02/calc/libreoffice/financial_model.xlsx differ diff --git a/results-2026-10-02/calc/results.json b/results-2026-10-02/calc/results.json new file mode 100644 index 0000000..c582600 --- /dev/null +++ b/results-2026-10-02/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": 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 + }, + "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-10-02/calc/wolfxl/financial_model.xlsx b/results-2026-10-02/calc/wolfxl/financial_model.xlsx new file mode 100644 index 0000000..64efb66 Binary files /dev/null and b/results-2026-10-02/calc/wolfxl/financial_model.xlsx differ diff --git a/results-2026-10-02/calc/zavora/financial_model.xlsx b/results-2026-10-02/calc/zavora/financial_model.xlsx new file mode 100644 index 0000000..9074d5b Binary files /dev/null and b/results-2026-10-02/calc/zavora/financial_model.xlsx differ diff --git a/results-2026-10-02/cross-language/CONTEXT.md b/results-2026-10-02/cross-language/CONTEXT.md new file mode 100644 index 0000000..13f0b5d --- /dev/null +++ b/results-2026-10-02/cross-language/CONTEXT.md @@ -0,0 +1,22 @@ +# 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: +- `apache-poi` +- `excelize` +- `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-10-02/cross-language/FIDELITY_DELTAS.md b/results-2026-10-02/cross-language/FIDELITY_DELTAS.md new file mode 100644 index 0000000..a91d7e9 --- /dev/null +++ b/results-2026-10-02/cross-language/FIDELITY_DELTAS.md @@ -0,0 +1,3 @@ +# Fidelity Deltas + +Need at least two runs in history.jsonl. diff --git a/results-2026-10-02/cross-language/README.md b/results-2026-10-02/cross-language/README.md new file mode 100644 index 0000000..5c2220f --- /dev/null +++ b/results-2026-10-02/cross-language/README.md @@ -0,0 +1,604 @@ +# ExcelBench Results + +*Generated: 2026-10-02 07:05 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 | apache-poi | excelize | zavora-xlsx | +|---------|:-:|:-:|:-:| +| Cell Values | 🟢 | 🟢 | 🔴 | +| Formulas | 🟢 | 🟢 | 🟢 | +| Sheets | 🟢 | 🟢 | 🟢 | + +**Tier 1 — Formatting** + +| Feature | apache-poi | excelize | zavora-xlsx | +|---------|:-:|:-:|:-:| +| Alignment | 🟢 | 🟢 | 🟠 | +| Bg Colors | 🟢 | 🟢 | 🟢 | +| Borders | 🟢 | 🟢 | 🔴 | +| Dimensions | 🟢 | 🟢 | 🟠 | +| Num Fmt | 🟢 | 🟢 | 🟢 | +| Text Fmt | 🟢 | 🟢 | 🟢 | + +**Tier 2 — Advanced** + +| Feature | apache-poi | excelize | zavora-xlsx | +|---------|:-:|:-:|:-:| +| chart_anchor | 🔴 | 🔴 | 🔴 | +| Comments | 🟢 | 🟢 | 🟢 | +| Cond Fmt | 🟢 | 🟢 | 🔴 | +| Validation | 🟢 | 🟢 | 🔴 | +| Freeze | 🟢 | 🟢 | 🔴 | +| Hyperlinks | 🟢 | 🟢 | 🔴 | +| Images | 🟢 | 🟢 | 🔴 | +| Merged | 🟢 | 🟢 | 🟢 | +| page_setup | 🔴 | 🔴 | 🔴 | +| sheet_protection | 🔴 | 🔴 | 🔴 | + +**Tier 3 — Workbook Metadata** + +| Feature | apache-poi | excelize | 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 | +|:----:|---------|:----:|:------:|:--------------:|---------| +| **S-** | apache-poi | W | No | 18/21 | 18/21 features with full fidelity | +| **S-** | excelize | W | No | 18/21 | 18/21 features with full fidelity | +| **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 | apache-poi (W) | excelize (W) | zavora-xlsx (W) | +|---------|------------|------------|------------| +| [cell_values](#cell_values-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [formulas](#formulas-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [multiple_sheets](#multiple_sheets-details) | 🟢 3 | 🟢 3 | 🟢 3 | + +**Tier 1 — Formatting** + +| Feature | apache-poi (W) | excelize (W) | zavora-xlsx (W) | +|---------|------------|------------|------------| +| [alignment](#alignment-details) | 🟢 3 | 🟢 3 | 🟠 1 | +| [background_colors](#background_colors-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [borders](#borders-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [dimensions](#dimensions-details) | 🟢 3 | 🟢 3 | 🟠 1 | +| [number_formats](#number_formats-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [text_formatting](#text_formatting-details) | 🟢 3 | 🟢 3 | 🟢 3 | + +**Tier 2 — Advanced** + +| Feature | apache-poi (W) | excelize (W) | zavora-xlsx (W) | +|---------|------------|------------|------------| +| [chart_anchor](#chart_anchor-details) | 🔴 0 | 🔴 0 | 🔴 0 | +| [comments](#comments-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [conditional_formatting](#conditional_formatting-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [data_validation](#data_validation-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [freeze_panes](#freeze_panes-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [hyperlinks](#hyperlinks-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [images](#images-details) | 🟢 3 | 🟢 3 | 🔴 0 | +| [merged_cells](#merged_cells-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [page_setup](#page_setup-details) | 🔴 0 | 🔴 0 | 🔴 0 | +| [pivot_tables](#pivot_tables-details) | ➖ | ➖ | ➖ | +| [sheet_protection](#sheet_protection-details) | 🔴 0 | 🔴 0 | 🔴 0 | + +**Tier 3 — Workbook Metadata** + +| Feature | apache-poi (W) | excelize (W) | zavora-xlsx (W) | +|---------|------------|------------|------------| +| [named_ranges](#named_ranges-details) | 🟢 3 | 🟢 3 | 🟢 3 | +| [tables](#tables-details) | 🟢 3 | 🟢 3 | 🟠 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 | +|---------|------|-------|--------|--------|-----------|----------------| +| apache-poi | W | 133 | 125 | 8 | 94% | 18/21 | +| excelize | W | 133 | 125 | 8 | 94% | 18/21 | +| zavora-xlsx | W | 133 | 63 | 70 | 47% | 8/21 | + +## Libraries Tested + +- **apache-poi** v5.5.1 (java) - write; modify: No +- **excelize** vgo-helper (go) - write; modify: No +- **zavora-xlsx** v0.1.2 (rust) - write; modify: No + +## Diagnostics Summary + +| Group | Value | Count | +|-------|-------|-------| +| category | data_mismatch | 4 | +| category | unsupported_feature | 82 | +| severity | error | 4 | +| severity | warning | 82 | + +### 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 | apache-poi | prot_basic | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement sheet protection writes | +| sheet_protection | apache-poi | prot_password | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement sheet protection writes | +| sheet_protection | apache-poi | prot_granular | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement sheet protection writes | +| sheet_protection | excelize | prot_basic | write | unsupported_feature | warning | NotImplementedError: excelize does not implement sheet protection writes | +| sheet_protection | excelize | prot_password | write | unsupported_feature | warning | NotImplementedError: excelize does not implement sheet protection writes | +| sheet_protection | excelize | prot_granular | write | unsupported_feature | warning | NotImplementedError: excelize does not implement sheet protection writes | +| 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 | apache-poi | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement page setup writes | +| page_setup | apache-poi | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement page setup writes | +| page_setup | apache-poi | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement page setup writes | +| page_setup | excelize | page_setup_landscape | write | unsupported_feature | warning | NotImplementedError: excelize does not implement page setup writes | +| page_setup | excelize | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: excelize does not implement page setup writes | +| page_setup | excelize | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: excelize does not implement page setup 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 | apache-poi | chart_bar | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement chart anchor writes | +| chart_anchor | apache-poi | chart_line | write | unsupported_feature | warning | NotImplementedError: apache-poi does not implement chart anchor writes | +| chart_anchor | excelize | chart_bar | write | unsupported_feature | warning | NotImplementedError: excelize does not implement chart anchor writes | +| chart_anchor | excelize | chart_line | write | unsupported_feature | warning | NotImplementedError: excelize does not implement chart anchor 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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### borders + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**excelize** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | + + +### comments + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### conditional_formatting + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### freeze_panes + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Hyperlink: external URL | basic | ❌ | +| Hyperlink: internal sheet | edge | ❌ | +| Hyperlink: mailto | basic | ❌ | +| Hyperlink: long encoded URL | edge | ❌ | + + +### images + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Image: one-cell anchor | basic | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | + + +### merged_cells + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### multiple_sheets + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### named_ranges + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### number_formats + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + + +### page_setup + +**apache-poi** — 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 | ❌ | + +**excelize** — 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 | ❌ | + +**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 + +**apache-poi** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**excelize** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**zavora-xlsx** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + + +### sheet_protection + +**apache-poi** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**excelize** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + +**zavora-xlsx** — Write: 🔴 0 + +| Test | Importance | Write | +|------|-----------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | +| Protection: with password hash | basic | ❌ | +| Protection: granular attribute flags | edge | ❌ | + + +### tables + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**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 + +**apache-poi** — Write: 🟢 3 + +**excelize** — Write: 🟢 3 + +**zavora-xlsx** — Write: 🟢 3 + +--- +*Benchmark version: 0.1.0* +## Scope (snapshot runner note) + +- `apache-poi` 5.5.1 and `excelize` 2.10.1 ran as Docker images `excelbench-poi-oracle:5.5.1` (`ef46106ed14d`) and `excelbench-excelize-oracle:2.10.1` (`425caf1a873f`) on Docker context `pc` (linux/amd64); `zavora-xlsx` 0.1.2 ran through local `cargo run`. +- **Adapter gap, not library gap:** the `sheet_protection`, `page_setup`, and `chart_anchor` 0 scores for `apache-poi` and `excelize` come from the ExcelBench Python adapters raising `NotImplementedError` ("does not implement ... writes"). Both libraries expose these features; the ExcelBench helpers have not been extended to Tier 4 yet. Read their 18/21 as "18 of 18 implemented Tier 0-3 features". +- The `excelize` version column reads `go-helper` because the adapter reports the helper, not the module; the image pins `github.com/xuri/excelize/v2` v2.10.1. + +Command: `EXCELBENCH_ORACLE_DOCKER_CONTEXT=pc excelbench cross-language-context -t fixtures/excel -o results-2026-10-02/cross-language`. diff --git a/results-2026-10-02/cross-language/WHY_FAILED.md b/results-2026-10-02/cross-language/WHY_FAILED.md new file mode 100644 index 0000000..0acd6b8 --- /dev/null +++ b/results-2026-10-02/cross-language/WHY_FAILED.md @@ -0,0 +1,517 @@ +# 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 / apache-poi / 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 / apache-poi / 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 / apache-poi / 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 / excelize / 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 / excelize / 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 / excelize / 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 / 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 / apache-poi / 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 / apache-poi / 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 / apache-poi / 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 / excelize / 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 / excelize / 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 / excelize / 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 / 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 / apache-poi / 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 / apache-poi / 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 / excelize / 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 / excelize / 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 / 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-10-02/cross-language/history.jsonl b/results-2026-10-02/cross-language/history.jsonl new file mode 100644 index 0000000..4f41a1f --- /dev/null +++ b/results-2026-10-02/cross-language/history.jsonl @@ -0,0 +1 @@ +{"run_date": "2026-10-02T07:05:19.195898+00:00", "commit": "b65866c", "profile": "xlsx", "scores": {"apache-poi": {"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": 3}, "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": 3}, "tables": {"read": null, "write": 3}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}, "excelize": {"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": 3}, "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": 3}, "tables": {"read": null, "write": 3}, "sheet_protection": {"read": null, "write": 0}, "page_setup": {"read": null, "write": 0}, "chart_anchor": {"read": null, "write": 0}}, "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-10-02/cross-language/matrix.csv b/results-2026-10-02/cross-language/matrix.csv new file mode 100644 index 0000000..0246491 --- /dev/null +++ b/results-2026-10-02/cross-language/matrix.csv @@ -0,0 +1,67 @@ +library,feature,read_score,write_score +apache-poi,cell_values,,3 +excelize,cell_values,,3 +zavora-xlsx,cell_values,,0 +apache-poi,formulas,,3 +excelize,formulas,,3 +zavora-xlsx,formulas,,3 +apache-poi,text_formatting,,3 +excelize,text_formatting,,3 +zavora-xlsx,text_formatting,,3 +apache-poi,background_colors,,3 +excelize,background_colors,,3 +zavora-xlsx,background_colors,,3 +apache-poi,number_formats,,3 +excelize,number_formats,,3 +zavora-xlsx,number_formats,,3 +apache-poi,alignment,,3 +excelize,alignment,,3 +zavora-xlsx,alignment,,1 +apache-poi,borders,,3 +excelize,borders,,3 +zavora-xlsx,borders,,0 +apache-poi,dimensions,,3 +excelize,dimensions,,3 +zavora-xlsx,dimensions,,1 +apache-poi,multiple_sheets,,3 +excelize,multiple_sheets,,3 +zavora-xlsx,multiple_sheets,,3 +apache-poi,merged_cells,,3 +excelize,merged_cells,,3 +zavora-xlsx,merged_cells,,3 +apache-poi,conditional_formatting,,3 +excelize,conditional_formatting,,3 +zavora-xlsx,conditional_formatting,,0 +apache-poi,data_validation,,3 +excelize,data_validation,,3 +zavora-xlsx,data_validation,,0 +apache-poi,hyperlinks,,3 +excelize,hyperlinks,,3 +zavora-xlsx,hyperlinks,,0 +apache-poi,images,,3 +excelize,images,,3 +zavora-xlsx,images,,0 +apache-poi,pivot_tables,, +excelize,pivot_tables,, +zavora-xlsx,pivot_tables,, +apache-poi,comments,,3 +excelize,comments,,3 +zavora-xlsx,comments,,3 +apache-poi,freeze_panes,,3 +excelize,freeze_panes,,3 +zavora-xlsx,freeze_panes,,0 +apache-poi,named_ranges,,3 +excelize,named_ranges,,3 +zavora-xlsx,named_ranges,,3 +apache-poi,tables,,3 +excelize,tables,,3 +zavora-xlsx,tables,,1 +apache-poi,sheet_protection,,0 +excelize,sheet_protection,,0 +zavora-xlsx,sheet_protection,,0 +apache-poi,page_setup,,0 +excelize,page_setup,,0 +zavora-xlsx,page_setup,,0 +apache-poi,chart_anchor,,0 +excelize,chart_anchor,,0 +zavora-xlsx,chart_anchor,,0 \ No newline at end of file diff --git a/results-2026-10-02/cross-language/results.json b/results-2026-10-02/cross-language/results.json new file mode 100644 index 0000000..e45f100 --- /dev/null +++ b/results-2026-10-02/cross-language/results.json @@ -0,0 +1,10415 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-10-02T07:05:19.195898+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx" + }, + "libraries": { + "apache-poi": { + "name": "apache-poi", + "version": "5.5.1", + "language": "java", + "capabilities": [ + "write" + ] + }, + "excelize": { + "name": "excelize", + "version": "go-helper", + "language": "go", + "capabilities": [ + "write" + ] + }, + "zavora-xlsx": { + "name": "zavora-xlsx", + "version": "0.1.2", + "language": "rust", + "capabilities": [ + "write" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "scores": { + "read": null, + "write": 3 + }, + "test_cases": { + "bold": { + "write": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold" + } + }, + "italic": { + "write": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Italic" + } + }, + "underline_single": { + "write": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - single" + } + }, + "underline_double": { + "write": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Underline - double" + } + }, + "strikethrough": { + "write": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Strikethrough" + } + }, + "bold_italic": { + "write": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Bold + Italic" + } + }, + "font_size_8": { + "write": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_size": 8.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 8" + } + }, + "font_size_14": { + "write": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_size": 14.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 14" + } + }, + "font_size_24": { + "write": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_size": 24.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 24" + } + }, + "font_size_36": { + "write": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_size": 36.0, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font size 36" + } + }, + "font_arial": { + "write": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_color": "#000000" + }, + "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_color": "#000000" + }, + "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_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font - Courier New" + } + }, + "color_red": { + "write": { + "passed": true, + "expected": { + "font_color": "#FF0000" + }, + "actual": { + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - red" + } + }, + "color_blue": { + "write": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - blue" + } + }, + "color_green": { + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + } + }, + "color_custom": { + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "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_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Combined - bold, 16pt, red" + } + } + }, + "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "scores": { + "read": null, + "write": 3 + }, + "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": 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": "alignment", + "library": "excelize", + "scores": { + "read": null, + "write": 3 + }, + "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": 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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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": "excelize", + "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": "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": "apache-poi", + "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.0 + }, + "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": "named_ranges", + "library": "excelize", + "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": "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": "apache-poi", + "scores": { + "read": null, + "write": 3 + }, + "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": 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": { + "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": "tables", + "library": "excelize", + "scores": { + "read": null, + "write": 3 + }, + "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": 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": { + "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": "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": "apache-poi", + "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": "apache-poi 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: apache-poi 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": "apache-poi 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: apache-poi 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": "apache-poi 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: apache-poi 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": "excelize", + "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": "excelize 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: excelize 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": "excelize 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: excelize 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": "excelize 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: excelize 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": "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": "apache-poi", + "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": "apache-poi 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: apache-poi 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": "apache-poi 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: apache-poi 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": "apache-poi 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: apache-poi 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": "excelize", + "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": "excelize 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: excelize 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": "excelize 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: excelize 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": "excelize 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: excelize 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": "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": "apache-poi", + "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": "apache-poi 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: apache-poi 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": "apache-poi 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: apache-poi 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": "excelize", + "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": "excelize 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: excelize 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": "excelize 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: excelize 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": "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-10-02/mutation/README.md b/results-2026-10-02/mutation/README.md new file mode 100644 index 0000000..2583f54 --- /dev/null +++ b/results-2026-10-02/mutation/README.md @@ -0,0 +1,34 @@ +# ExcelBench Mutation Results + +*Generated: 2026-10-02T08:10:41Z* +*Template SHA-256: da08cc9e607f267b438ec7ce2480d6eb3650d1c19928f283a18296a2b79d808e* +*Repeats: 3* + +## Comparison + +| Engine | Wall ms | Peak RSS KB | Features preserved | Unexpected changes | Edits applied | Integrity | Verdict | +|--------|---------|-------------|--------------------|--------------------|---------------|-----------|---------| +| aspose-cells-foss | 1140.000 | 160512.000 | 15/17 | cells (87), custom_xml (1) | yes | ok | Changed cells, custom_xml | +| exceljs | — | — | — | — | — | — | Failed | +| libreoffice | 2550.000 | 264432.000 | 15/17 | cell_styles (16), page_setup (5) | yes | ok | Changed cell_styles, page_setup | +| openpyxl | 1560.000 | 159904.000 | 16/17 | custom_xml (1) | yes | ok | Changed custom_xml | +| sheetjs | 1160.000 | 159248.000 | 8/17 | cell_styles (9), views (3), data_validations (2), conditional_formats (2), protection (1), page_setup (2), charts (2), tables (1), custom_xml (1) | yes | ok | Changed cell_styles, views, data_validations, conditional_formats, protection, page_setup, charts, tables, custom_xml | +| wolfxl | 1470.000 | 162112.000 | 17/17 | none | yes | ok | Preserved | +| zavora-xlsx | 1910.000 | 159184.000 | 8/17 | cells (48), cell_styles (17), data_validations (2), conditional_formats (2), comments (1), charts (2), tables (1), theme (1), custom_xml (1) | yes | ok | Changed cells, cell_styles, data_validations, conditional_formats, comments, charts, tables, theme, custom_xml | + +## Notes + +Wall time and peak RSS are measured in isolated subprocesses with macOS `/usr/bin/time -l`. +Preservation compares the output's workbook content model against the template's model with the two declared cell edits applied. Part names, relationship ids, XML serialization and document metadata are not content, so an equivalent rewrite scores the same as a byte copy. Cached results of formula cells are recalculation state and are not compared; formula text is. Features preserved counts template features with no unexpected difference. Integrity (dangling relationships, parts without a content type) is reported separately and is not scored. This does not measure formula recalculation or rendering. + +## Scope (snapshot runner note) + +- **Scorer.** Rerun on 2026-10-02 with the content-model scorer: the template's xlsx content model (vendored verbatim from `officelibs-corpus/src/officecorpus/model/xlsx.py`, sha256 `17fb55bc132caf91a23f07e1df35423dda7f5e14051837f88dd708ccf7b19e61`) with the two declared edits applied is compared with the output's model, plus a `custom_xml` feature (canonical XML and datastore item id). Part names, relationship ids, XML encoding and metadata are not scored. This replaces the earlier part-name/byte score (40 parts + 30 elements + 20 integrity + 10 byte-identical customXml), which scored a byte copy 100 by construction. +- **Old score -> new verdict.** wolfxl 100 -> Preserved (17/17); openpyxl 60 -> Changed custom_xml (16/17); LibreOffice 70 -> Changed cell_styles, page_setup (15/17); aspose-cells-foss 60 -> Changed cells, custom_xml (15/17); SheetJS 20 -> Changed cell_styles, views, data_validations, conditional_formats, protection, page_setup, charts, tables, custom_xml (8/17); zavora-xlsx 0 (integrity-failed) -> Changed cells, cell_styles, data_validations, conditional_formats, comments, charts, tables, theme, custom_xml (8/17); ExcelJS Failed -> Failed. +- **What each engine changes.** openpyxl drops the custom XML data item. LibreOffice gives the header row (`Inputs!A1:H1`), whose font the template leaves without a name or size, Cambria 11 (16 cell_styles diffs) and changes header/footer margins from 0.5 in to 0.512 in on Inputs and Schedule plus the Summary footer (5 page_setup diffs); its comment written as `xl/comments1.xml` and its re-serialized customXml, which cost it 30 points before, are no longer counted. aspose-cells-foss drops 87 string cells across all three sheets and the custom XML item. SheetJS drops the header-row styles, all three freeze panes, both data validations, both conditional formats, the Schedule sheet protection, the Summary landscape orientation and page header, both charts, the table and custom XML, and changes the default font size from 11 to 12. zavora-xlsx blanks 48 string cells on Inputs, gives the header-row font Calibri 11 and the default font color white (`FFFFFF` instead of theme 1) (17 cell_styles diffs), changes the decimal validation's allow-blank flag and drops the cellIs rule's fill, and drops the comment, both charts, the table, the referenced theme color and custom XML. Per-feature counts and the first 10 diffs per engine are in `results.json`. +- **zavora-xlsx edits.** Both declared edits land (`edits_applied: true`). The previous `integrity-failed` came from the openpyxl verifier, which cannot open this output (`IndexError` on an out-of-range style index); the content model reads it. +- **Timing is not comparable.** `vm.loadavg` was `{ 36.85 75.08 147.92 }` immediately before the run (08:10:09Z) and `{ 26.92 68.35 142.52 }` right after it (08:10:45Z), far above 16, because of unrelated host load. Wall-ms and RSS are recorded as measured but must not be compared with each other or with 2026-09-08. Preservation verdicts do not depend on timing. +- `exceljs` 4.4.0 failed: ExcelJS throws `Cannot read properties of undefined (reading 'anchors')` while loading the template (full traceback in `results.json`). +- `apache-poi` and `excelize` are not in this lane: their ExcelBench helpers are write-only (no open-existing-workbook operation), and the suite times each engine in a local `/usr/bin/time -l` subprocess, which a remote container cannot provide. + +Command: `excelbench mutation -o results-2026-10-02/mutation --repeats 3`. diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-input.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-output.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-output.xlsx new file mode 100644 index 0000000..e2e17bf Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-input.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-output.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-output.xlsx new file mode 100644 index 0000000..be56102 Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-input.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-output.xlsx b/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-output.xlsx new file mode 100644 index 0000000..be56102 Binary files /dev/null and b/results-2026-10-02/mutation/aspose-cells-foss/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/mutation/exceljs/repeat-1-input.xlsx b/results-2026-10-02/mutation/exceljs/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/exceljs/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-1-input.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-1-output.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-1-output.xlsx new file mode 100644 index 0000000..df20d74 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-2-input.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-2-output.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-2-output.xlsx new file mode 100644 index 0000000..25077f8 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-3-input.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/libreoffice/repeat-3-output.xlsx b/results-2026-10-02/mutation/libreoffice/repeat-3-output.xlsx new file mode 100644 index 0000000..c675635 Binary files /dev/null and b/results-2026-10-02/mutation/libreoffice/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-1-input.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-1-output.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-1-output.xlsx new file mode 100644 index 0000000..5feea57 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-2-input.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-2-output.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-2-output.xlsx new file mode 100644 index 0000000..e47cae8 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-3-input.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/openpyxl/repeat-3-output.xlsx b/results-2026-10-02/mutation/openpyxl/repeat-3-output.xlsx new file mode 100644 index 0000000..1fbdb49 Binary files /dev/null and b/results-2026-10-02/mutation/openpyxl/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/mutation/results.json b/results-2026-10-02/mutation/results.json new file mode 100644 index 0000000..9f94f70 --- /dev/null +++ b/results-2026-10-02/mutation/results.json @@ -0,0 +1,1318 @@ +{ + "engines": { + "aspose-cells-foss": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [ + "xl/sharedStrings.xml" + ], + "element_changes": [], + "lost_parts": [ + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml" + ] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-aspose-cells-foss" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-aspose-cells-foss" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [ + { + "after": null, + "before": { + "type": "s", + "value": "Driver" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A1" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 09" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A10" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 10" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A11" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 11" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A12" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 12" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A13" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 13" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A14" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 14" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A15" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 15" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A16" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 16" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A17" + }, + { + "after": null, + "before": { + "type": "s", + "value": "Input 17" + }, + "feature": "cells", + "kind": "missing", + "path": "/cells/Inputs/A18" + } + ] + }, + "edits_applied": true, + "feature_preservation": "15/17", + "features_changed": { + "cells": 87, + "custom_xml": 1 + }, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 160512.0, + "preserved": false, + "status": "passed", + "verdict": "Changed cells, custom_xml", + "wall_ms_median": 1140.0 + }, + "exceljs": { + "available": true, + "details": { + "error": "RuntimeError: Traceback (most recent call last):\n File \"\", line 9, in \n engine.mutate(Path(template), Path(output), json.loads(mutations))\n ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/src/excelbench/modifiable.py\", line 223, in mutate\n self._adapter().mutate_file(template, output, mutations)\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/src/excelbench/harness/adapters/json_model_adapter.py\", line 545, in mutate_file\n cls.call_helper(\n ~~~~~~~~~~~~~~~^\n \"mutate\",\n ^^^^^^^^^\n ...<2 lines>...\n output_path=output,\n ^^^^^^^^^^^^^^^^^^^\n )\n ^\n File \"/src/excelbench/harness/adapters/json_model_adapter.py\", line 215, in call_helper\n raise HelperError(f\"{tool.name} {operation} failed: {message}\")\nexcelbench.harness.adapters.json_model_adapter.HelperError: exceljs mutate failed: Cannot read properties of undefined (reading 'anchors')\n 1.23 real 0.90 user 0.25 sys\n 163250176 maximum resident set size\n 0 average shared memory size\n 0 average unshared data size\n 0 average unshared stack size\n 30874 page reclaims\n 1 page faults\n 0 swaps\n 0 block input operations\n 0 block output operations\n 0 messages sent\n 0 messages received\n 0 signals received\n 844 voluntary context switches\n 5876 involuntary context switches\n 5711758120 instructions retired\n 3188498838 cycles elapsed\n 125748016 peak memory footprint" + }, + "edits_applied": null, + "feature_preservation": null, + "features_changed": null, + "features_present": null, + "peak_rss_kb_median": null, + "preserved": null, + "status": "failed", + "verdict": "Failed", + "wall_ms_median": null + }, + "libreoffice": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [ + "docProps/custom.xml", + "xl/charts/_rels/chart1.xml.rels", + "xl/charts/_rels/chart2.xml.rels", + "xl/charts/colors1.xml", + "xl/charts/colors2.xml", + "xl/charts/style1.xml", + "xl/charts/style2.xml", + "xl/comments1.xml", + "xl/drawings/vmlDrawing1.vml", + "xl/sharedStrings.xml" + ], + "element_changes": [ + { + "element": "pageSetup", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": false, + "present_in_output": true + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": true + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": false, + "present_in_output": true + } + ], + "lost_parts": [ + "xl/comments/comment1.xml", + "xl/drawings/commentsDrawing1.vml" + ] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-libreoffice" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-libreoffice" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [ + { + "after": "Cambria", + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/A1/font/name" + }, + { + "after": 11.0, + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/A1/font/size" + }, + { + "after": "Cambria", + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/B1/font/name" + }, + { + "after": 11.0, + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/B1/font/size" + }, + { + "after": "Cambria", + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/C1/font/name" + }, + { + "after": 11.0, + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/C1/font/size" + }, + { + "after": "Cambria", + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/D1/font/name" + }, + { + "after": 11.0, + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/D1/font/size" + }, + { + "after": "Cambria", + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/E1/font/name" + }, + { + "after": 11.0, + "before": null, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/sheets/Inputs/E1/font/size" + } + ] + }, + "edits_applied": true, + "feature_preservation": "15/17", + "features_changed": { + "cell_styles": 16, + "page_setup": 5 + }, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 264432.0, + "preserved": false, + "status": "passed", + "verdict": "Changed cell_styles, page_setup", + "wall_ms_median": 2550.0 + }, + "openpyxl": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [], + "element_changes": [], + "lost_parts": [ + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml" + ] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-openpyxl" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-openpyxl" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [ + { + "after": null, + "before": { + "count": 1, + "item_id": "{11111111-2222-3333-4444-555555555555}", + "schemas": [], + "xml": "openpyxl-targeted-fixture" + }, + "feature": "custom_xml", + "kind": "missing", + "path": "/custom_xml/923316dfc82cc7cb" + } + ] + }, + "edits_applied": true, + "feature_preservation": "16/17", + "features_changed": { + "custom_xml": 1 + }, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 159904.0, + "preserved": false, + "status": "passed", + "verdict": "Changed custom_xml", + "wall_ms_median": 1560.0 + }, + "sheetjs": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [ + "xl/comments1.xml", + "xl/drawings/vmlDrawing1.vml", + "xl/metadata.xml" + ], + "element_changes": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "dataValidations", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "conditionalFormatting", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "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": false + }, + { + "element": "sheetProtection", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "pane", + "part": "xl/worksheets/sheet2.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "pageSetup", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "headerFooter", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "pane", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "drawing", + "part": "xl/worksheets/sheet3.xml", + "present_in_original": true, + "present_in_output": false + } + ], + "lost_parts": [ + "customXml/_rels/item1.xml.rels", + "customXml/item1.xml", + "customXml/itemProps1.xml", + "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/tables/table1.xml", + "xl/worksheets/_rels/sheet3.xml.rels" + ] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-sheetjs" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-sheetjs" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [ + { + "after": 12.0, + "before": 11.0, + "feature": "cell_styles", + "kind": "changed", + "path": "/cell_styles/default/font/size" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/A1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/B1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/C1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/D1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/E1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/F1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/G1" + }, + { + "after": null, + "before": { + "alignment": { + "horizontal": "general", + "indent": 0, + "justify_last_line": false, + "reading_order": 0, + "shrink_to_fit": false, + "text_rotation": 0, + "vertical": "bottom", + "wrap_text": false + }, + "border": { + "bottom": { + "style": "none" + }, + "left": { + "style": "none" + }, + "right": { + "style": "none" + }, + "top": { + "style": "none" + } + }, + "fill": { + "fg": "1F4E78", + "pattern": "solid" + }, + "font": { + "bold": true, + "color": "FFFFFF", + "italic": false, + "name": null, + "size": null, + "strike": false, + "underline": "none", + "vert_align": "baseline" + }, + "number_format": "General", + "protection": { + "hidden": false, + "locked": true + } + }, + "feature": "cell_styles", + "kind": "missing", + "path": "/cell_styles/sheets/Inputs/H1" + }, + { + "after": null, + "before": { + "cols": 1, + "rows": 1 + }, + "feature": "views", + "kind": "missing", + "path": "/views/Inputs/freeze" + } + ] + }, + "edits_applied": true, + "feature_preservation": "8/17", + "features_changed": { + "cell_styles": 9, + "charts": 2, + "conditional_formats": 2, + "custom_xml": 1, + "data_validations": 2, + "page_setup": 2, + "protection": 1, + "tables": 1, + "views": 3 + }, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 159248.0, + "preserved": false, + "status": "passed", + "verdict": "Changed cell_styles, views, data_validations, conditional_formats, protection, page_setup, charts, tables, custom_xml", + "wall_ms_median": 1160.0 + }, + "wolfxl": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [ + "xl/calcChain.xml" + ], + "element_changes": [], + "lost_parts": [] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-wolfxl" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-wolfxl" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [] + }, + "edits_applied": true, + "feature_preservation": "17/17", + "features_changed": {}, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 162112.0, + "preserved": true, + "status": "passed", + "verdict": "Preserved", + "wall_ms_median": 1470.0 + }, + "zavora-xlsx": { + "available": true, + "details": { + "diagnostics": { + "added_parts": [ + "xl/sharedStrings.xml" + ], + "element_changes": [ + { + "element": "tableParts", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + }, + { + "element": "sheetPr", + "part": "xl/worksheets/sheet1.xml", + "present_in_original": true, + "present_in_output": false + } + ], + "lost_parts": [ + "xl/worksheets/_rels/sheet3.xml.rels" + ] + }, + "edits": [ + { + "actual": { + "type": "s", + "value": "MUTATED-zavora-xlsx" + }, + "applied": true, + "cell": "B2", + "expected": { + "type": "s", + "value": "MUTATED-zavora-xlsx" + }, + "sheet": "Inputs" + }, + { + "actual": { + "type": "n", + "value": 1337.0 + }, + "applied": true, + "cell": "C3", + "expected": { + "type": "n", + "value": 1337.0 + }, + "sheet": "Inputs" + } + ], + "integrity": { + "dangling_rels": [], + "missing_content_types": [] + }, + "sample": [ + { + "after": "", + "before": "Driver", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A1/value" + }, + { + "after": "", + "before": "Input 09", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A10/value" + }, + { + "after": "", + "before": "Input 10", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A11/value" + }, + { + "after": "", + "before": "Input 11", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A12/value" + }, + { + "after": "", + "before": "Input 12", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A13/value" + }, + { + "after": "", + "before": "Input 13", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A14/value" + }, + { + "after": "", + "before": "Input 14", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A15/value" + }, + { + "after": "", + "before": "Input 15", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A16/value" + }, + { + "after": "", + "before": "Input 16", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A17/value" + }, + { + "after": "", + "before": "Input 17", + "feature": "cells", + "kind": "changed", + "path": "/cells/Inputs/A18/value" + } + ] + }, + "edits_applied": true, + "feature_preservation": "8/17", + "features_changed": { + "cell_styles": 17, + "cells": 48, + "charts": 2, + "comments": 1, + "conditional_formats": 2, + "custom_xml": 1, + "data_validations": 2, + "tables": 1, + "theme": 1 + }, + "features_present": [ + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "columns", + "views", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "charts", + "tables", + "theme", + "custom_xml" + ], + "peak_rss_kb_median": 159184.0, + "preserved": false, + "status": "passed", + "verdict": "Changed cells, cell_styles, data_validations, conditional_formats, comments, charts, tables, theme, custom_xml", + "wall_ms_median": 1910.0 + } + }, + "metadata": { + "platform": "Darwin", + "repeats": 3, + "template_sha256": "da08cc9e607f267b438ec7ce2480d6eb3650d1c19928f283a18296a2b79d808e", + "timestamp": "2026-10-02T08:10:41Z" + } +} diff --git a/results-2026-10-02/mutation/sheetjs/repeat-1-input.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/sheetjs/repeat-1-output.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-1-output.xlsx new file mode 100644 index 0000000..21105ff Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/sheetjs/repeat-2-input.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/sheetjs/repeat-2-output.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-2-output.xlsx new file mode 100644 index 0000000..21105ff Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/sheetjs/repeat-3-input.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/sheetjs/repeat-3-output.xlsx b/results-2026-10-02/mutation/sheetjs/repeat-3-output.xlsx new file mode 100644 index 0000000..21105ff Binary files /dev/null and b/results-2026-10-02/mutation/sheetjs/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-1-input.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-1-output.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-1-output.xlsx new file mode 100644 index 0000000..eaf4a1f Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-2-input.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-2-output.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-2-output.xlsx new file mode 100644 index 0000000..0abc92d Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-3-input.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/wolfxl/repeat-3-output.xlsx b/results-2026-10-02/mutation/wolfxl/repeat-3-output.xlsx new file mode 100644 index 0000000..0abc92d Binary files /dev/null and b/results-2026-10-02/mutation/wolfxl/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-1-input.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-1-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-1-input.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-1-output.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-1-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-1-output.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-2-input.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-2-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-2-input.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-2-output.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-2-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-2-output.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-3-input.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-3-input.xlsx new file mode 100644 index 0000000..8614250 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-3-input.xlsx differ diff --git a/results-2026-10-02/mutation/zavora-xlsx/repeat-3-output.xlsx b/results-2026-10-02/mutation/zavora-xlsx/repeat-3-output.xlsx new file mode 100644 index 0000000..14b5814 Binary files /dev/null and b/results-2026-10-02/mutation/zavora-xlsx/repeat-3-output.xlsx differ diff --git a/results-2026-10-02/perf/README.md b/results-2026-10-02/perf/README.md new file mode 100644 index 0000000..e393c58 --- /dev/null +++ b/results-2026-10-02/perf/README.md @@ -0,0 +1,376 @@ +# ExcelBench Performance Results + +*Generated: 2026-10-02T08:33:41.795781+00:00* +*Profile: xlsx* +*Platform: Darwin-arm64* +*Python: 3.12.3* +*CPU: arm* +*Cores: 14 | Memory MB: 24576.0* +*Config: warmup=3 iters=25 iteration_policy=fixed breakdown=False* + +## Run Receipt + +Fresh rerun of the 2026-04-29 perf scenario (`results-release-2026-04-28/perf/`) with +the WolfXL 2.0.5 PyPI wheel, the same build every other 2026-10-02 lane uses. WolfXL +2.0.6 was released to PyPI at 2026-10-02T07:55Z and is **not** measured here. + +### Adapter path change + +The 2026-04-28 release snapshot (and the 2026-04-20 `results/perf/` snapshot) measured +WolfXL through private backend objects in `wolfxl._rust`, while every other library was +measured through its public API. Those WolfXL numbers are not comparable with the other +libraries' numbers and are superseded by this run, which measures WolfXL 2.0.5 through its +public API (`wolfxl.load_workbook`, `wolfxl.Workbook`) like every other library. + +### Source identity + +- ExcelBench commit: `a9b223c268ad2c68a5314bee51810619550607d4` (local branch `officelibs-m2`), + tree `edc3fe0316aea9d6f38de6505ae30ae1fcb1fe0b`. Local history was squashed before + publication, so that commit id is not on GitHub. Its published equivalent is + `8db6afaebc3a5aef515da933608838780491a244`, which has the identical tree: + `git rev-parse 8db6afa^{tree}` prints `edc3fe0316aea9d6f38de6505ae30ae1fcb1fe0b`. + `metadata.commit` in `results.json` is `null` because the harness reads + `git rev-parse` and the staged tree is a git archive, not a checkout; the staging + receipt below is the source identity. +- Staged from a clean detached `git worktree` at that commit (no dirty or untracked overlay). +- Staging receipt (`remote-source-sync run`): + +```json +{"action": "run", "schema_version": "remote-source-sync.v1", "mode": "git-archive-tar-gzip-1+dirty-overlay", + "head": "a9b223c268ad2c68a5314bee51810619550607d4", "source_key": "a9b223c268ad2c68a5314bee51810619550607d4", + "tracked_files": 551, "dirty_files": 0, "deleted_files": 0, "excluded_generated_files": 0, + "allowed_sensitive_files": 0, "target": "m4", "remote_dir": "~/wolf-lane/officelibs-perf/src", + "replaces_remote_directory": true, "transfer_ok": true} +``` + +- Fixture manifest `fixtures/excel/manifest.json` sha256 + `984073b67669fb0566b55e35a05447fbaaeb9f0da2d6de1a335baf61de9b382f` (identical locally and on + the host). The 19 measured fixture files are byte-identical to those in 0bf80c9, the commit + that checked in April's snapshot (April's recorded commit `5f98de9` was squashed and is not + in history); the manifest only gained the three Tier 4 entries, which the `--feature` + filter excludes. + +### Host + +- Apple Mac16,8, Apple M4 Pro, 14 cores, 24 GB RAM; macOS 26.6.2 (25G83), Darwin 25.6.0. + Headless worker with sleep disabled. (`run_environment.cpu_model` reads `arm` + because the harness uses `platform.processor()`.) +- Resident non-benchmark load: one long-running background agent process at ~97% of one + core for the whole window (not stopped; it is not ours). No other job of ours ran during + the measurement. +- 1-minute load gate: wait until load1 <= 4.0 (10 s poll, 10 min cap). + - Load before: `{ 3.81 3.75 2.87 }` at 2026-10-02T08:33:41Z (gate passed after 70 s; load was + 7.59 at 08:32:30Z). + - Load after: `{ 3.62 3.72 2.87 }` at 2026-10-02T08:33:54Z. + - An earlier attempt at 08:31:59Z started at load1 9.63 (Spotlight `mds` at ~60% and an + unrelated agent server at ~58% CPU) without the gate; it was discarded unread and is not + part of this snapshot. + +### Interpreter and packages + +- CPython 3.12.3 (python-build-standalone via uv, Clang 17.0.6), matching April's 3.12.3. + Fresh `uv venv` (uv 0.12.5), default PyPI index, no index overrides. +- Pinned adapter packages (`pins.txt`): wolfxl 2.0.5, openpyxl 3.1.5, xlsxwriter 3.2.9, + python-calamine 0.8.2, pylightxl 1.61, xlrd 2.0.2, pyexcel 0.7.6, pyexcel-xlsx 0.6.1, + xlwt 1.3.0, pandas 3.0.6, polars 1.44.2, fastexcel 0.21.0, tablib 3.10.0 (each the PyPI + latest on 2026-10-02, except wolfxl). Full environment: `pip-freeze.txt`. +- WolfXL: `wolfxl.__version__ == "2.0.5"`, wheel `wolfxl-2.0.5-cp312-cp312-macosx_11_0_arm64.whl` + (maturin 1.14.1), sha256 `599b6ac753b1d32e2e68eb54c37d060c66f6a65f8378d725cda4b15b2b4f5e2b` + (equal to the PyPI digest; re-downloaded and hashed on the host). The installed + `wolfxl/_rust.cpython-312-darwin.so` sha256 + `3beda732f3def27570cf071689f7a8691a0818d0a3464e075fc1b183c0cd1dc0` equals the copy inside + that wheel. + +### Command + +Run from the staged source root by `run.sh` (log: `run-log.txt`; wall 13.1 s, exit 0): + +```bash +excelbench perf --tests fixtures/excel --output ../out --profile xlsx \ + --warmup 3 --iters 25 --iteration-policy fixed --memory-mode getrusage \ + --feature cell_values --feature formulas --feature text_formatting --feature background_colors \ + --feature number_formats --feature alignment --feature borders --feature dimensions \ + --feature multiple_sheets --feature merged_cells --feature conditional_formatting \ + --feature data_validation --feature hyperlinks --feature images --feature pivot_tables \ + --feature comments --feature freeze_panes --feature named_ranges --feature tables \ + --adapter openpyxl --adapter xlsxwriter --adapter python-calamine --adapter wolfxl \ + --adapter pylightxl --adapter xlrd --adapter pyexcel --adapter xlwt --adapter pandas \ + --adapter xlsxwriter-constmem --adapter openpyxl-readonly --adapter polars --adapter tablib +``` + +- Warmup 3, recorded iterations 25, policy `fixed`, breakdown off, memory mode `getrusage` + (all harness defaults, same as April). The perf harness has no per-operation timeout. +- The explicit feature and adapter lists reproduce April's 19 features and 13 adapters in + April's order (the current manifest has 22 features). Every adapter gets the same + fixtures, warmup, and iteration count; nothing is WolfXL-specific. +- Cold vs warm: the harness runs every (feature, adapter, operation) in one process, + discards the first 3 iterations as warmup, and reports min/p50/p95 over the next 25. + All reported numbers are warm in-process timings. Cold-start cost (interpreter start, + imports, first-open) is not measured by this lane. + +### Scenario differences from April + +- **WolfXL adapter path.** April's adapter drove `wolfxl._rust` backend objects directly + (`CalamineStyledBook` for reads, a native writer book for writes; version string + `cal=2.0.0+rxw=2.0.0`). Since 2026-09-07 (5524cac) the adapter uses WolfXL's public + openpyxl-compatible API (`wolfxl.load_workbook`, `wolfxl.Workbook`), the same kind of + surface every other library is measured through. The published 2.0.0 and 2.0.5 wheels do + not expose `CalamineStyledBook`, so April's adapter cannot run against them. + Diagnostic (`diagnostics/`, same host, same harness, openpyxl as control, run back to + back at 08:35Z): p50 totals over the 19 features are WolfXL 2.0.0 read 13.57 ms / write + 22.13 ms vs 2.0.5 read 13.82 ms / write 22.86 ms (openpyxl 23.16/26.57 vs 22.96/26.64). + The change from April's WolfXL numbers comes from the adapter path, not a 2.0.0 to 2.0.5 + regression. +- **Unsupported writes are now failures, not timed no-ops** (a7ef0b8). pyexcel and pylightxl + write timings now cover 5 features (April: 19) and xlwt 14 (April: 19); the rest appear + under Run Issues as `UnsupportedAdapterOperationError`. Their write totals are not + comparable to April's without restricting to common features. +- **Library versions** moved for python-calamine (0.6.1 to 0.8.2), pyexcel (0.7.4 to 0.7.6), + pandas (3.0.0 to 3.0.6), polars (1.38.1 to 1.44.2), and tablib (3.9.0 to 3.10.0). +- **Host.** April's results record only `Darwin-arm64`; the April host model is not recorded, + so cross-snapshot absolute deltas mix host and version effects. +- `excel_version` 16.105.3 in `results.json` is the fixture manifest's generator metadata, + not software used by this run. + +### Artifacts + +- `results.json`, `README.md` (this file; summary tables below are harness output), + `matrix.csv`, `history.jsonl`: harness output. +- `run.sh`, `run-log.txt`: the exact driver and its log (home prefix replaced with `~`, one + unrelated process path redacted; `.txt` because the repo ignores `*.log`). +- `pins.txt`, `pip-freeze.txt`: requested pins and the resolved environment. +- `diagnostics/wolfxl-2.0.0-current-adapter.results.json`, + `diagnostics/wolfxl-2.0.5-current-adapter.results.json`: the WolfXL version-isolation + diagnostic above (openpyxl + wolfxl only). Not part of the snapshot. + +### Per-adapter p50 totals vs April (sum of per-feature p50 wall ms; n = features measured) + +| Adapter | April version | Oct version | Op | April total (n) | Oct total (n) | Oct / April on common features | +|---|---|---|---|---|---|---| +| openpyxl | 3.1.5 | 3.1.5 | read | 25.07 (19) | 22.79 (19) | 0.91x | +| openpyxl | 3.1.5 | 3.1.5 | write | 31.68 (19) | 26.70 (19) | 0.84x | +| xlsxwriter | 3.2.9 | 3.2.9 | write | 39.64 (19) | 31.12 (19) | 0.79x | +| python-calamine | 0.6.1 | 0.8.2 | read | 2.16 (19) | 1.63 (19) | 0.75x | +| wolfxl | cal=2.0.0+rxw=2.0.0 | 2.0.5 | read | 4.19 (19) | 13.46 (19) | 3.21x (adapter path changed) | +| wolfxl | cal=2.0.0+rxw=2.0.0 | 2.0.5 | write | 3.64 (19) | 22.28 (19) | 6.12x (adapter path changed) | +| pylightxl | 1.61 | 1.61 | read | 11.69 (10) | 10.55 (10) | 0.90x | +| pylightxl | 1.61 | 1.61 | write | 6.14 (19) | 1.21 (5) | 0.81x (5 common) | +| pyexcel | 0.7.4 | 0.7.6 | read | 27.66 (19) | 24.92 (19) | 0.90x | +| pyexcel | 0.7.4 | 0.7.6 | write | 29.77 (19) | 7.28 (5) | 0.86x (5 common) | +| xlwt | 1.3.0 | 1.3.0 | write | 3.84 (19) | 2.90 (14) | 0.93x (14 common) | +| pandas | 3.0.0 | 3.0.6 | read | 31.96 (19) | 28.43 (19) | 0.89x | +| pandas | 3.0.0 | 3.0.6 | write | 34.71 (19) | 26.66 (19) | 0.77x | +| xlsxwriter-constmem | 3.2.9 | 3.2.9 | write | 39.51 (19) | 31.17 (19) | 0.79x | +| openpyxl-readonly | 3.1.5 | 3.1.5 | read | 23.11 (19) | 22.75 (19) | 0.98x | +| polars | 1.38.1 | 1.44.2 | read | 6.88 (19) | 6.13 (19) | 0.89x | +| tablib | 3.9.0 | 3.10.0 | read | 24.45 (19) | 23.09 (19) | 0.94x | +| tablib | 3.9.0 | 3.10.0 | write | 29.45 (19) | 23.58 (19) | 0.80x | + +xlrd has no timings in either snapshot (it does not read `.xlsx`). + +## Notes + +These numbers measure only the library under test. Write timings do NOT include oracle verification. +Confidence note: treat deltas under ~5% as noise unless stable across multiple runs. + +## Summary (p50 wall time) + +**Tier 0 — Basic Values** + +| Feature | openpyxl (R p50/p95 ms) | openpyxl (W p50/p95 ms) | openpyxl-readonly (R p50/p95 ms) | pandas (R p50/p95 ms) | pandas (W p50/p95 ms) | polars (R p50/p95 ms) | pyexcel (R p50/p95 ms) | pyexcel (W p50/p95 ms) | pylightxl (R p50/p95 ms) | pylightxl (W p50/p95 ms) | python-calamine (R p50/p95 ms) | tablib (R p50/p95 ms) | tablib (W p50/p95 ms) | wolfxl (R p50/p95 ms) | wolfxl (W p50/p95 ms) | xlrd (R p50/p95 ms) | xlsxwriter (W p50/p95 ms) | xlsxwriter-constmem (W p50/p95 ms) | xlwt (W p50/p95 ms) | +|---------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------| +| cell_values | 1.26/1.55 | 1.22/1.29 | 5.69/5.94 | 1.71/1.82 | 1.48/1.55 | 0.32/0.42 | 1.40/1.44 | — | 1.26/1.28 | — | 0.62/0.63 | 1.37/1.40 | 1.30/1.38 | 0.66/0.73 | 1.18/1.28 | — | 1.59/2.03 | 1.59/2.00 | 0.22/0.28 | +| formulas | 1.11/1.13 | 1.35/1.41 | 1.43/1.67 | 1.52/1.55 | 1.60/1.86 | 0.41/0.54 | 1.19/1.24 | 1.39/1.47 | 1.12/1.14 | 0.26/0.29 | 0.12/0.12 | 1.16/1.19 | 1.37/1.43 | 0.57/0.63 | 1.17/1.33 | — | 1.53/1.99 | 1.71/2.17 | 0.26/0.34 | +| multiple_sheets | 1.31/1.41 | 1.74/1.93 | 0.97/1.01 | 1.76/1.84 | 2.02/2.37 | 0.52/0.69 | 1.65/2.73 | 2.31/2.69 | 1.29/1.44 | 0.32/0.38 | 0.06/0.06 | 1.31/1.35 | 1.71/2.52 | 0.54/0.58 | 1.30/1.50 | — | 1.95/2.41 | 2.00/2.45 | 0.18/0.18 | + +**Tier 1 — Formatting** + +| Feature | openpyxl (R p50/p95 ms) | openpyxl (W p50/p95 ms) | openpyxl-readonly (R p50/p95 ms) | pandas (R p50/p95 ms) | pandas (W p50/p95 ms) | polars (R p50/p95 ms) | pyexcel (R p50/p95 ms) | pyexcel (W p50/p95 ms) | pylightxl (R p50/p95 ms) | pylightxl (W p50/p95 ms) | python-calamine (R p50/p95 ms) | tablib (R p50/p95 ms) | tablib (W p50/p95 ms) | wolfxl (R p50/p95 ms) | wolfxl (W p50/p95 ms) | xlrd (R p50/p95 ms) | xlsxwriter (W p50/p95 ms) | xlsxwriter-constmem (W p50/p95 ms) | xlwt (W p50/p95 ms) | +|---------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------| +| alignment | 1.18/1.22 | 1.32/1.40 | 0.92/0.96 | 1.42/1.54 | 1.35/1.41 | 0.22/0.27 | 1.23/1.27 | — | — | — | 0.05/0.05 | 1.21/1.38 | 1.16/1.22 | 0.65/0.69 | 1.10/1.18 | — | 1.58/1.85 | 1.63/1.99 | 0.22/0.23 | +| background_colors | 0.98/1.03 | 1.20/1.25 | 0.84/0.87 | 1.20/1.30 | 1.30/1.36 | 0.24/0.32 | 1.04/1.08 | — | 0.90/0.91 | — | 0.05/0.06 | 0.99/1.02 | 1.11/1.19 | 0.58/0.65 | 1.12/1.23 | — | 1.57/1.97 | 1.55/1.97 | 0.18/0.19 | +| borders | 1.68/1.80 | 2.06/2.32 | 1.27/1.31 | 2.00/2.27 | 1.48/1.54 | 0.26/0.32 | 1.76/1.80 | — | — | — | 0.06/0.07 | 1.76/2.10 | 1.32/1.48 | 0.98/1.01 | 1.40/1.50 | — | 2.01/2.46 | 1.95/2.32 | 0.39/0.45 | +| dimensions | 0.94/1.04 | 1.24/1.30 | 0.84/0.93 | 1.46/1.63 | 1.29/1.43 | 0.36/0.45 | 1.01/1.05 | — | 0.87/0.89 | — | 0.05/0.05 | 1.03/1.18 | 1.24/1.37 | 0.52/0.56 | 1.04/1.18 | — | 1.35/1.85 | 1.64/2.24 | 0.16/0.22 | +| number_formats | 1.01/1.06 | 1.17/1.20 | 0.86/0.88 | 1.23/1.28 | 1.32/1.71 | 0.24/0.29 | 1.06/1.12 | — | 0.93/0.95 | — | 0.06/0.06 | 1.01/1.11 | 1.12/1.17 | 0.59/0.63 | 1.08/1.34 | — | 1.39/1.88 | 1.74/1.97 | 0.19/0.24 | +| text_formatting | 1.67/1.70 | 1.79/1.85 | 1.42/1.46 | 1.94/1.96 | 1.44/1.54 | 0.25/0.30 | 1.73/1.79 | — | 1.42/1.46 | — | 0.07/0.08 | 1.73/1.85 | 1.25/1.32 | 0.84/0.90 | 1.22/1.30 | — | 1.82/2.23 | 1.92/2.22 | 0.34/0.63 | + +**Tier 2 — Advanced** + +| Feature | openpyxl (R p50/p95 ms) | openpyxl (W p50/p95 ms) | openpyxl-readonly (R p50/p95 ms) | pandas (R p50/p95 ms) | pandas (W p50/p95 ms) | polars (R p50/p95 ms) | pyexcel (R p50/p95 ms) | pyexcel (W p50/p95 ms) | pylightxl (R p50/p95 ms) | pylightxl (W p50/p95 ms) | python-calamine (R p50/p95 ms) | tablib (R p50/p95 ms) | tablib (W p50/p95 ms) | wolfxl (R p50/p95 ms) | wolfxl (W p50/p95 ms) | xlrd (R p50/p95 ms) | xlsxwriter (W p50/p95 ms) | xlsxwriter-constmem (W p50/p95 ms) | xlwt (W p50/p95 ms) | +|---------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------| +| comments | 1.07/1.09 | 1.35/1.45 | 0.84/0.88 | 1.17/1.22 | 1.22/1.28 | 0.23/0.27 | 1.13/1.27 | — | 1.08/1.10 | — | 0.05/0.06 | 0.97/1.02 | 1.07/1.27 | 1.11/1.19 | 1.21/1.27 | — | 1.77/2.27 | 1.36/1.62 | — | +| conditional_formatting | 1.35/1.40 | 1.59/1.76 | 0.91/0.95 | 1.71/1.73 | 1.43/1.56 | 0.36/0.50 | 1.45/1.60 | — | — | — | 0.05/0.05 | 1.38/1.41 | 1.32/1.44 | 0.99/1.04 | 1.22/1.28 | — | 1.62/2.08 | 1.72/2.14 | — | +| data_validation | 1.20/1.24 | 1.19/1.34 | 0.85/0.92 | 1.61/1.75 | 1.18/1.25 | 0.51/0.69 | 1.31/1.62 | — | — | — | 0.05/0.05 | 1.32/1.48 | 1.05/1.10 | 0.58/0.64 | 1.08/1.11 | — | 1.41/1.77 | 1.46/1.85 | — | +| freeze_panes | 1.33/1.36 | 1.85/2.03 | 0.95/0.99 | 1.73/1.88 | 2.00/2.28 | 0.44/0.52 | 1.45/1.52 | — | — | — | 0.05/0.05 | 1.36/1.41 | 1.81/2.01 | 0.67/0.71 | 1.30/1.49 | — | 1.75/2.27 | 2.01/2.60 | 0.18/0.20 | +| hyperlinks | 1.14/1.17 | 1.18/1.21 | 0.89/1.02 | 1.51/1.55 | 1.19/1.32 | 0.36/0.48 | 1.26/1.35 | — | — | — | 0.05/0.05 | 1.21/1.28 | 1.08/1.15 | 1.12/1.17 | 1.13/1.28 | — | 1.68/2.12 | 1.68/1.89 | — | +| images | 1.10/1.17 | 1.65/1.76 | 0.77/0.81 | 1.11/1.15 | 1.17/1.24 | 0.22/0.27 | 1.17/1.24 | — | — | — | 0.05/0.05 | 0.93/0.95 | 1.06/1.13 | 0.85/0.90 | 1.42/1.55 | — | 2.32/2.80 | 1.39/1.82 | — | +| merged_cells | 1.19/1.23 | 1.28/1.32 | 0.86/0.88 | 1.26/1.28 | 1.35/1.43 | 0.23/0.27 | 1.27/1.30 | — | 0.93/0.95 | — | 0.05/0.06 | 1.05/1.06 | 1.13/1.22 | 0.80/0.87 | 1.10/1.37 | — | 1.49/2.04 | 1.49/1.94 | 0.18/0.19 | +| named_ranges | 1.09/1.13 | 1.37/1.48 | 0.85/0.87 | 1.45/1.51 | 1.46/1.51 | 0.41/0.50 | 1.20/1.43 | 1.39/1.51 | — | 0.23/0.23 | 0.05/0.05 | 1.15/1.17 | 1.33/1.44 | 0.47/0.52 | 1.13/1.19 | — | 1.65/2.20 | 1.57/1.81 | 0.15/0.16 | +| pivot_tables | 0.81/0.84 | 1.08/1.13 | 0.69/0.75 | 1.03/1.08 | 1.18/1.27 | 0.20/0.25 | 0.88/0.92 | 1.08/1.13 | 0.77/0.83 | 0.20/0.21 | 0.05/0.05 | 0.82/0.85 | 1.05/1.12 | 0.47/0.51 | 1.03/1.12 | — | 1.31/1.69 | 1.39/1.91 | 0.12/0.13 | +| tables | 1.40/1.44 | 1.08/1.13 | 0.90/1.05 | 1.61/1.68 | 1.20/1.25 | 0.37/0.48 | 1.72/2.02 | 1.11/1.73 | — | 0.20/0.22 | 0.05/0.05 | 1.33/1.46 | 1.08/1.12 | 0.51/0.53 | 1.04/1.07 | — | 1.33/1.70 | 1.38/1.79 | 0.13/0.13 | + +## Run Issues + +- alignment / openpyxl-readonly: Write unsupported +- alignment / polars: Write unsupported +- alignment / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells +- alignment / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature +- alignment / python-calamine: Write unsupported +- alignment / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- alignment / xlsxwriter-constmem: Read unsupported +- alignment / xlsxwriter: Read unsupported +- alignment / xlwt: Read unsupported +- background_colors / openpyxl-readonly: Write unsupported +- background_colors / polars: Write unsupported +- background_colors / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells +- background_colors / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature +- background_colors / python-calamine: Write unsupported +- background_colors / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- background_colors / xlsxwriter-constmem: Read unsupported +- background_colors / xlsxwriter: Read unsupported +- background_colors / xlwt: Read unsupported +- borders / openpyxl-readonly: Write unsupported +- borders / polars: Write unsupported +- borders / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells +- borders / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature +- borders / python-calamine: Write unsupported +- borders / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- borders / xlsxwriter-constmem: Read unsupported +- borders / xlsxwriter: Read unsupported +- borders / xlwt: Read unsupported +- cell_values / openpyxl-readonly: Write unsupported +- cell_values / polars: Write unsupported +- cell_values / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells +- cell_values / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature +- cell_values / python-calamine: Write unsupported +- cell_values / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- cell_values / xlsxwriter-constmem: Read unsupported +- cell_values / xlsxwriter: Read unsupported +- cell_values / xlwt: Read unsupported +- comments / openpyxl-readonly: Write unsupported +- comments / polars: Write unsupported +- comments / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature +- comments / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature +- comments / python-calamine: Write unsupported +- comments / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- comments / xlsxwriter-constmem: Read unsupported +- comments / xlsxwriter: Read unsupported +- comments / xlwt: Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments +- conditional_formatting / openpyxl-readonly: Write unsupported +- conditional_formatting / polars: Write unsupported +- conditional_formatting / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature +- conditional_formatting / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature +- conditional_formatting / python-calamine: Write unsupported +- conditional_formatting / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- conditional_formatting / xlsxwriter-constmem: Read unsupported +- conditional_formatting / xlsxwriter: Read unsupported +- conditional_formatting / xlwt: Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting +- data_validation / openpyxl-readonly: Write unsupported +- data_validation / polars: Write unsupported +- data_validation / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature +- data_validation / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature +- data_validation / python-calamine: Write unsupported +- data_validation / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- data_validation / xlsxwriter-constmem: Read unsupported +- data_validation / xlsxwriter: Read unsupported +- data_validation / xlwt: Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations +- dimensions / openpyxl-readonly: Write unsupported +- dimensions / polars: Write unsupported +- dimensions / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing +- dimensions / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature +- dimensions / python-calamine: Write unsupported +- dimensions / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- dimensions / xlsxwriter-constmem: Read unsupported +- dimensions / xlsxwriter: Read unsupported +- dimensions / xlwt: Read unsupported +- formulas / openpyxl-readonly: Write unsupported +- formulas / polars: Write unsupported +- formulas / python-calamine: Write unsupported +- formulas / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- formulas / xlsxwriter-constmem: Read unsupported +- formulas / xlsxwriter: Read unsupported +- formulas / xlwt: Read unsupported +- freeze_panes / openpyxl-readonly: Write unsupported +- freeze_panes / polars: Write unsupported +- freeze_panes / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature +- freeze_panes / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature +- freeze_panes / python-calamine: Write unsupported +- freeze_panes / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- freeze_panes / xlsxwriter-constmem: Read unsupported +- freeze_panes / xlsxwriter: Read unsupported +- freeze_panes / xlwt: Read unsupported +- hyperlinks / openpyxl-readonly: Write unsupported +- hyperlinks / polars: Write unsupported +- hyperlinks / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature +- hyperlinks / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature +- hyperlinks / python-calamine: Write unsupported +- hyperlinks / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- hyperlinks / xlsxwriter-constmem: Read unsupported +- hyperlinks / xlsxwriter: Read unsupported +- hyperlinks / xlwt: Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter +- images / openpyxl-readonly: Write unsupported +- images / polars: Write unsupported +- images / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature +- images / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature +- images / python-calamine: Write unsupported +- images / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- images / xlsxwriter-constmem: Read unsupported +- images / xlsxwriter: Read unsupported +- images / xlwt: Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter +- merged_cells / openpyxl-readonly: Write unsupported +- merged_cells / polars: Write unsupported +- merged_cells / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature +- merged_cells / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature +- merged_cells / python-calamine: Write unsupported +- merged_cells / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- merged_cells / xlsxwriter-constmem: Read unsupported +- merged_cells / xlsxwriter: Read unsupported +- merged_cells / xlwt: Read unsupported +- multiple_sheets / openpyxl-readonly: Write unsupported +- multiple_sheets / polars: Write unsupported +- multiple_sheets / python-calamine: Write unsupported +- multiple_sheets / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- multiple_sheets / xlsxwriter-constmem: Read unsupported +- multiple_sheets / xlsxwriter: Read unsupported +- multiple_sheets / xlwt: Read unsupported +- named_ranges / openpyxl-readonly: Write unsupported +- named_ranges / polars: Write unsupported +- named_ranges / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType' +- named_ranges / python-calamine: Write unsupported +- named_ranges / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- named_ranges / xlsxwriter-constmem: Read unsupported +- named_ranges / xlsxwriter: Read unsupported +- named_ranges / xlwt: Read unsupported +- number_formats / openpyxl-readonly: Write unsupported +- number_formats / polars: Write unsupported +- number_formats / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells +- number_formats / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature +- number_formats / python-calamine: Write unsupported +- number_formats / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- number_formats / xlsxwriter-constmem: Read unsupported +- number_formats / xlsxwriter: Read unsupported +- number_formats / xlwt: Read unsupported +- pivot_tables / openpyxl-readonly: Write unsupported +- pivot_tables / polars: Write unsupported +- pivot_tables / python-calamine: Write unsupported +- pivot_tables / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- pivot_tables / xlsxwriter-constmem: Read unsupported +- pivot_tables / xlsxwriter: Read unsupported +- pivot_tables / xlwt: Read unsupported +- tables / openpyxl-readonly: Write unsupported +- tables / polars: Write unsupported +- tables / pylightxl: Read failed: TypeError: expected string or bytes-like object, got 'NoneType' +- tables / python-calamine: Write unsupported +- tables / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- tables / xlsxwriter-constmem: Read unsupported +- tables / xlsxwriter: Read unsupported +- tables / xlwt: Read unsupported +- text_formatting / openpyxl-readonly: Write unsupported +- text_formatting / polars: Write unsupported +- text_formatting / pyexcel: Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells +- text_formatting / pylightxl: Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature +- text_formatting / python-calamine: Write unsupported +- text_formatting / xlrd: Write unsupported; Read not applicable: xlrd does not support .xlsx input +- text_formatting / xlsxwriter-constmem: Read unsupported +- text_formatting / xlsxwriter: Read unsupported +- text_formatting / xlwt: Read unsupported diff --git a/results-2026-10-02/perf/diagnostics/wolfxl-2.0.0-current-adapter.results.json b/results-2026-10-02/perf/diagnostics/wolfxl-2.0.0-current-adapter.results.json new file mode 100644 index 0000000..8ef8d54 --- /dev/null +++ b/results-2026-10-02/perf/diagnostics/wolfxl-2.0.0-current-adapter.results.json @@ -0,0 +1,2097 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-10-02T08:35:17.241870+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx", + "python": "3.12.3", + "commit": null, + "config": { + "warmup": 3, + "iters": 25, + "iteration_policy": "fixed", + "breakdown": false + }, + "run_environment": { + "cpu_model": "arm", + "core_count": 14, + "memory_total_mb": 24576.0 + } + }, + "libraries": { + "openpyxl": { + "name": "openpyxl", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "wolfxl": { + "name": "wolfxl", + "version": "2.0.0", + "language": "python", + "capabilities": [ + "modify", + "read", + "write" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.201541, + "p50": 1.276667, + "p95": 1.323042 + }, + "cpu_ms": { + "min": 1.201, + "p50": 1.276, + "p95": 1.322 + }, + "rss_peak_mb": 186.0625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.276667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.217042, + "p50": 1.290125, + "p95": 1.634708 + }, + "cpu_ms": { + "min": 1.218, + "p50": 1.29, + "p95": 1.627 + }, + "rss_peak_mb": 186.28125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.290125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.653042, + "p50": 0.661834, + "p95": 0.739875 + }, + "cpu_ms": { + "min": 0.653, + "p50": 0.662, + "p95": 0.74 + }, + "rss_peak_mb": 187.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.661834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.166292, + "p50": 1.189458, + "p95": 1.324875 + }, + "cpu_ms": { + "min": 1.167, + "p50": 1.189, + "p95": 1.325 + }, + "rss_peak_mb": 188.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.189458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.063917, + "p50": 1.122459, + "p95": 1.154209 + }, + "cpu_ms": { + "min": 1.065, + "p50": 1.122, + "p95": 1.155 + }, + "rss_peak_mb": 188.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.122459, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.311792, + "p50": 1.352958, + "p95": 1.418625 + }, + "cpu_ms": { + "min": 1.313, + "p50": 1.352, + "p95": 1.418 + }, + "rss_peak_mb": 188.171875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.352958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.553042, + "p50": 0.573833, + "p95": 0.640541 + }, + "cpu_ms": { + "min": 0.553, + "p50": 0.574, + "p95": 0.641 + }, + "rss_peak_mb": 188.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.573833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.141167, + "p50": 1.179209, + "p95": 1.294709 + }, + "cpu_ms": { + "min": 1.142, + "p50": 1.18, + "p95": 1.296 + }, + "rss_peak_mb": 188.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.179209, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.653459, + "p50": 1.686291, + "p95": 1.925125 + }, + "cpu_ms": { + "min": 1.654, + "p50": 1.686, + "p95": 1.925 + }, + "rss_peak_mb": 188.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.686291, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.636625, + "p50": 1.755375, + "p95": 1.815416 + }, + "cpu_ms": { + "min": 1.637, + "p50": 1.755, + "p95": 1.815 + }, + "rss_peak_mb": 188.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.755375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.814917, + "p50": 0.868125, + "p95": 1.015542 + }, + "cpu_ms": { + "min": 0.816, + "p50": 0.868, + "p95": 1.007 + }, + "rss_peak_mb": 188.484375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.868125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.176667, + "p50": 1.20875, + "p95": 1.278541 + }, + "cpu_ms": { + "min": 1.176, + "p50": 1.208, + "p95": 1.279 + }, + "rss_peak_mb": 188.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.20875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.927583, + "p50": 0.979667, + "p95": 1.021875 + }, + "cpu_ms": { + "min": 0.927, + "p50": 0.98, + "p95": 1.022 + }, + "rss_peak_mb": 188.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.979667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.191959, + "p50": 1.237416, + "p95": 1.3085 + }, + "cpu_ms": { + "min": 1.193, + "p50": 1.237, + "p95": 1.308 + }, + "rss_peak_mb": 188.6875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.237416, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.549708, + "p50": 0.577875, + "p95": 0.663709 + }, + "cpu_ms": { + "min": 0.55, + "p50": 0.579, + "p95": 0.655 + }, + "rss_peak_mb": 188.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.577875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.052208, + "p50": 1.074583, + "p95": 1.17375 + }, + "cpu_ms": { + "min": 1.052, + "p50": 1.075, + "p95": 1.173 + }, + "rss_peak_mb": 188.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.074583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.961916, + "p50": 1.017417, + "p95": 1.044084 + }, + "cpu_ms": { + "min": 0.962, + "p50": 1.018, + "p95": 1.044 + }, + "rss_peak_mb": 188.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.017417, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.173917, + "p50": 1.223167, + "p95": 1.270125 + }, + "cpu_ms": { + "min": 1.174, + "p50": 1.223, + "p95": 1.27 + }, + "rss_peak_mb": 188.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.223167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.579708, + "p50": 0.608625, + "p95": 0.679167 + }, + "cpu_ms": { + "min": 0.579, + "p50": 0.608, + "p95": 0.678 + }, + "rss_peak_mb": 188.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.608625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.069792, + "p50": 1.090542, + "p95": 1.150041 + }, + "cpu_ms": { + "min": 1.07, + "p50": 1.091, + "p95": 1.15 + }, + "rss_peak_mb": 188.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.090542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.1205, + "p50": 1.189458, + "p95": 1.283542 + }, + "cpu_ms": { + "min": 1.12, + "p50": 1.19, + "p95": 1.283 + }, + "rss_peak_mb": 188.84375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.189458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.251959, + "p50": 1.345833, + "p95": 1.558125 + }, + "cpu_ms": { + "min": 1.252, + "p50": 1.346, + "p95": 1.558 + }, + "rss_peak_mb": 188.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.345833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.627792, + "p50": 0.64675, + "p95": 0.709125 + }, + "cpu_ms": { + "min": 0.629, + "p50": 0.646, + "p95": 0.709 + }, + "rss_peak_mb": 188.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.64675, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.065542, + "p50": 1.105625, + "p95": 1.176042 + }, + "cpu_ms": { + "min": 1.066, + "p50": 1.106, + "p95": 1.176 + }, + "rss_peak_mb": 188.921875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.105625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.662375, + "p50": 1.691542, + "p95": 1.72575 + }, + "cpu_ms": { + "min": 1.662, + "p50": 1.691, + "p95": 1.726 + }, + "rss_peak_mb": 189.328125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.691542, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 2.067084, + "p50": 2.097041, + "p95": 2.156958 + }, + "cpu_ms": { + "min": 2.067, + "p50": 2.097, + "p95": 2.157 + }, + "rss_peak_mb": 189.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.097041, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.9165, + "p50": 0.977583, + "p95": 1.076916 + }, + "cpu_ms": { + "min": 0.918, + "p50": 0.978, + "p95": 1.077 + }, + "rss_peak_mb": 189.6875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.977583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.349, + "p50": 1.398875, + "p95": 1.546334 + }, + "cpu_ms": { + "min": 1.349, + "p50": 1.399, + "p95": 1.546 + }, + "rss_peak_mb": 189.984375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.398875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.87975, + "p50": 0.929084, + "p95": 0.964167 + }, + "cpu_ms": { + "min": 0.88, + "p50": 0.93, + "p95": 0.964 + }, + "rss_peak_mb": 189.984375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.929084, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.078542, + "p50": 1.119291, + "p95": 1.174291 + }, + "cpu_ms": { + "min": 1.078, + "p50": 1.118, + "p95": 1.174 + }, + "rss_peak_mb": 190.0, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.119291, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.508292, + "p50": 0.535042, + "p95": 0.576416 + }, + "cpu_ms": { + "min": 0.508, + "p50": 0.534, + "p95": 0.571 + }, + "rss_peak_mb": 190.015625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.535042, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.008667, + "p50": 1.018375, + "p95": 1.06925 + }, + "cpu_ms": { + "min": 1.008, + "p50": 1.019, + "p95": 1.069 + }, + "rss_peak_mb": 190.03125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.018375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.223541, + "p50": 1.249583, + "p95": 1.294583 + }, + "cpu_ms": { + "min": 1.224, + "p50": 1.249, + "p95": 1.294 + }, + "rss_peak_mb": 190.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.249583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.5535, + "p50": 1.580583, + "p95": 1.743458 + }, + "cpu_ms": { + "min": 1.553, + "p50": 1.58, + "p95": 1.743 + }, + "rss_peak_mb": 190.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.580583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.485708, + "p50": 0.517, + "p95": 0.555375 + }, + "cpu_ms": { + "min": 0.485, + "p50": 0.517, + "p95": 0.556 + }, + "rss_peak_mb": 190.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.517, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.149042, + "p50": 1.165833, + "p95": 1.225792 + }, + "cpu_ms": { + "min": 1.149, + "p50": 1.166, + "p95": 1.226 + }, + "rss_peak_mb": 190.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.165833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.138417, + "p50": 1.194, + "p95": 1.240333 + }, + "cpu_ms": { + "min": 1.138, + "p50": 1.194, + "p95": 1.241 + }, + "rss_peak_mb": 190.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.194, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.236917, + "p50": 1.306583, + "p95": 1.376666 + }, + "cpu_ms": { + "min": 1.237, + "p50": 1.307, + "p95": 1.377 + }, + "rss_peak_mb": 190.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.306583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.761583, + "p50": 0.7835, + "p95": 0.818708 + }, + "cpu_ms": { + "min": 0.761, + "p50": 0.784, + "p95": 0.818 + }, + "rss_peak_mb": 190.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.7835, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.063333, + "p50": 1.094625, + "p95": 1.1455 + }, + "cpu_ms": { + "min": 1.063, + "p50": 1.095, + "p95": 1.145 + }, + "rss_peak_mb": 190.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.094625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.351083, + "p50": 1.383208, + "p95": 1.41725 + }, + "cpu_ms": { + "min": 1.351, + "p50": 1.383, + "p95": 1.418 + }, + "rss_peak_mb": 190.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.383208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.585708, + "p50": 1.610209, + "p95": 1.761917 + }, + "cpu_ms": { + "min": 1.586, + "p50": 1.61, + "p95": 1.762 + }, + "rss_peak_mb": 190.484375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.610209, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.976, + "p50": 1.0065, + "p95": 1.061666 + }, + "cpu_ms": { + "min": 0.976, + "p50": 1.007, + "p95": 1.062 + }, + "rss_peak_mb": 191.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.0065, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.168625, + "p50": 1.236125, + "p95": 1.357 + }, + "cpu_ms": { + "min": 1.169, + "p50": 1.236, + "p95": 1.357 + }, + "rss_peak_mb": 191.3125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.236125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.178625, + "p50": 1.2175, + "p95": 1.2605 + }, + "cpu_ms": { + "min": 1.178, + "p50": 1.217, + "p95": 1.261 + }, + "rss_peak_mb": 191.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.2175, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.142958, + "p50": 1.196667, + "p95": 1.360792 + }, + "cpu_ms": { + "min": 1.144, + "p50": 1.197, + "p95": 1.356 + }, + "rss_peak_mb": 191.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.196667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.56625, + "p50": 0.578167, + "p95": 0.646291 + }, + "cpu_ms": { + "min": 0.566, + "p50": 0.578, + "p95": 0.646 + }, + "rss_peak_mb": 191.625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.578167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.059, + "p50": 1.076542, + "p95": 1.166167 + }, + "cpu_ms": { + "min": 1.059, + "p50": 1.075, + "p95": 1.166 + }, + "rss_peak_mb": 191.65625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.076542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.129708, + "p50": 1.171667, + "p95": 1.202708 + }, + "cpu_ms": { + "min": 1.13, + "p50": 1.171, + "p95": 1.202 + }, + "rss_peak_mb": 191.8125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.171667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.151125, + "p50": 1.205708, + "p95": 1.258209 + }, + "cpu_ms": { + "min": 1.151, + "p50": 1.206, + "p95": 1.259 + }, + "rss_peak_mb": 191.8125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.205708, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.094917, + "p50": 1.121375, + "p95": 1.186166 + }, + "cpu_ms": { + "min": 1.094, + "p50": 1.121, + "p95": 1.186 + }, + "rss_peak_mb": 192.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.121375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.107875, + "p50": 1.124792, + "p95": 1.1715 + }, + "cpu_ms": { + "min": 1.107, + "p50": 1.124, + "p95": 1.171 + }, + "rss_peak_mb": 192.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.124792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.201459, + "p50": 1.316834, + "p95": 1.793041 + }, + "cpu_ms": { + "min": 1.201, + "p50": 1.317, + "p95": 1.792 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.316834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.475417, + "p50": 1.541291, + "p95": 1.759667 + }, + "cpu_ms": { + "min": 1.476, + "p50": 1.541, + "p95": 1.748 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.541291, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.841709, + "p50": 0.878917, + "p95": 0.912208 + }, + "cpu_ms": { + "min": 0.842, + "p50": 0.879, + "p95": 0.913 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.878917, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.372958, + "p50": 1.424958, + "p95": 1.601083 + }, + "cpu_ms": { + "min": 1.373, + "p50": 1.425, + "p95": 1.601 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.424958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.770834, + "p50": 0.817959, + "p95": 0.846083 + }, + "cpu_ms": { + "min": 0.77, + "p50": 0.818, + "p95": 0.846 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.817959, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.031292, + "p50": 1.087208, + "p95": 1.146042 + }, + "cpu_ms": { + "min": 1.031, + "p50": 1.088, + "p95": 1.144 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.087208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.443333, + "p50": 0.465833, + "p95": 0.5335 + }, + "cpu_ms": { + "min": 0.444, + "p50": 0.466, + "p95": 0.534 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.465833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.013167, + "p50": 1.062667, + "p95": 1.145584 + }, + "cpu_ms": { + "min": 1.012, + "p50": 1.042, + "p95": 1.138 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.062667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.0245, + "p50": 1.08325, + "p95": 1.109333 + }, + "cpu_ms": { + "min": 1.024, + "p50": 1.084, + "p95": 1.11 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.08325, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.279709, + "p50": 1.317583, + "p95": 1.356333 + }, + "cpu_ms": { + "min": 1.28, + "p50": 1.317, + "p95": 1.356 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.317583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.075541, + "p50": 1.101834, + "p95": 1.175875 + }, + "cpu_ms": { + "min": 1.076, + "p50": 1.102, + "p95": 1.176 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.101834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.2035, + "p50": 1.246666, + "p95": 1.320208 + }, + "cpu_ms": { + "min": 1.204, + "p50": 1.247, + "p95": 1.321 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.246666, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.279458, + "p50": 1.327541, + "p95": 1.632833 + }, + "cpu_ms": { + "min": 1.279, + "p50": 1.327, + "p95": 1.633 + }, + "rss_peak_mb": 193.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.327541, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.769625, + "p50": 1.86625, + "p95": 2.038542 + }, + "cpu_ms": { + "min": 1.77, + "p50": 1.867, + "p95": 2.039 + }, + "rss_peak_mb": 193.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.86625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.642, + "p50": 0.674125, + "p95": 0.791041 + }, + "cpu_ms": { + "min": 0.642, + "p50": 0.674, + "p95": 0.792 + }, + "rss_peak_mb": 193.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.674125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.246375, + "p50": 1.270042, + "p95": 1.324417 + }, + "cpu_ms": { + "min": 1.246, + "p50": 1.27, + "p95": 1.325 + }, + "rss_peak_mb": 193.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.270042, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.024125, + "p50": 1.084583, + "p95": 1.123375 + }, + "cpu_ms": { + "min": 1.024, + "p50": 1.084, + "p95": 1.123 + }, + "rss_peak_mb": 193.90625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.084583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.27675, + "p50": 1.342458, + "p95": 1.49025 + }, + "cpu_ms": { + "min": 1.277, + "p50": 1.342, + "p95": 1.491 + }, + "rss_peak_mb": 193.90625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.342458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.448, + "p50": 0.476625, + "p95": 0.528459 + }, + "cpu_ms": { + "min": 0.448, + "p50": 0.477, + "p95": 0.529 + }, + "rss_peak_mb": 193.90625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.476625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.083709, + "p50": 1.117083, + "p95": 1.148375 + }, + "cpu_ms": { + "min": 1.083, + "p50": 1.117, + "p95": 1.148 + }, + "rss_peak_mb": 193.921875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.117083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.374291, + "p50": 1.419167, + "p95": 1.467417 + }, + "cpu_ms": { + "min": 1.374, + "p50": 1.42, + "p95": 1.468 + }, + "rss_peak_mb": 194.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.419167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.0375, + "p50": 1.094667, + "p95": 1.238625 + }, + "cpu_ms": { + "min": 1.037, + "p50": 1.094, + "p95": 1.239 + }, + "rss_peak_mb": 194.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.094667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.49325, + "p50": 0.512208, + "p95": 0.547417 + }, + "cpu_ms": { + "min": 0.493, + "p50": 0.512, + "p95": 0.547 + }, + "rss_peak_mb": 194.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.512208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.004917, + "p50": 1.044375, + "p95": 1.109959 + }, + "cpu_ms": { + "min": 1.004, + "p50": 1.044, + "p95": 1.11 + }, + "rss_peak_mb": 194.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.044375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/results-2026-10-02/perf/diagnostics/wolfxl-2.0.5-current-adapter.results.json b/results-2026-10-02/perf/diagnostics/wolfxl-2.0.5-current-adapter.results.json new file mode 100644 index 0000000..070cf01 --- /dev/null +++ b/results-2026-10-02/perf/diagnostics/wolfxl-2.0.5-current-adapter.results.json @@ -0,0 +1,2097 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-10-02T08:35:20.989510+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx", + "python": "3.12.3", + "commit": null, + "config": { + "warmup": 3, + "iters": 25, + "iteration_policy": "fixed", + "breakdown": false + }, + "run_environment": { + "cpu_model": "arm", + "core_count": 14, + "memory_total_mb": 24576.0 + } + }, + "libraries": { + "openpyxl": { + "name": "openpyxl", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "wolfxl": { + "name": "wolfxl", + "version": "2.0.5", + "language": "python", + "capabilities": [ + "modify", + "read", + "write" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.233917, + "p50": 1.27575, + "p95": 1.564875 + }, + "cpu_ms": { + "min": 1.234, + "p50": 1.276, + "p95": 1.565 + }, + "rss_peak_mb": 154.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.27575, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.202208, + "p50": 1.267875, + "p95": 1.438459 + }, + "cpu_ms": { + "min": 1.203, + "p50": 1.268, + "p95": 1.439 + }, + "rss_peak_mb": 154.953125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.267875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.666958, + "p50": 0.6825, + "p95": 0.747917 + }, + "cpu_ms": { + "min": 0.668, + "p50": 0.682, + "p95": 0.749 + }, + "rss_peak_mb": 156.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.6825, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.166667, + "p50": 1.211333, + "p95": 1.319958 + }, + "cpu_ms": { + "min": 1.167, + "p50": 1.212, + "p95": 1.32 + }, + "rss_peak_mb": 157.015625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.211333, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.065083, + "p50": 1.115625, + "p95": 1.146667 + }, + "cpu_ms": { + "min": 1.064, + "p50": 1.116, + "p95": 1.147 + }, + "rss_peak_mb": 157.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.115625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.294542, + "p50": 1.352417, + "p95": 1.516792 + }, + "cpu_ms": { + "min": 1.295, + "p50": 1.353, + "p95": 1.517 + }, + "rss_peak_mb": 157.28125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.352417, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.567209, + "p50": 0.58675, + "p95": 0.642041 + }, + "cpu_ms": { + "min": 0.567, + "p50": 0.587, + "p95": 0.642 + }, + "rss_peak_mb": 157.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.58675, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.161083, + "p50": 1.200292, + "p95": 1.391208 + }, + "cpu_ms": { + "min": 1.161, + "p50": 1.201, + "p95": 1.392 + }, + "rss_peak_mb": 157.375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.200292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.6605, + "p50": 1.694625, + "p95": 1.783333 + }, + "cpu_ms": { + "min": 1.661, + "p50": 1.695, + "p95": 1.78 + }, + "rss_peak_mb": 157.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.694625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.592584, + "p50": 1.647375, + "p95": 1.706042 + }, + "cpu_ms": { + "min": 1.592, + "p50": 1.647, + "p95": 1.706 + }, + "rss_peak_mb": 157.921875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.647375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.836875, + "p50": 0.855083, + "p95": 0.921167 + }, + "cpu_ms": { + "min": 0.837, + "p50": 0.855, + "p95": 0.921 + }, + "rss_peak_mb": 157.953125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.855083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.226583, + "p50": 1.285667, + "p95": 1.405625 + }, + "cpu_ms": { + "min": 1.226, + "p50": 1.287, + "p95": 1.405 + }, + "rss_peak_mb": 158.375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.285667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.923625, + "p50": 0.980125, + "p95": 1.011916 + }, + "cpu_ms": { + "min": 0.924, + "p50": 0.98, + "p95": 1.012 + }, + "rss_peak_mb": 158.375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.980125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.196333, + "p50": 1.263833, + "p95": 1.294 + }, + "cpu_ms": { + "min": 1.196, + "p50": 1.264, + "p95": 1.295 + }, + "rss_peak_mb": 158.375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.263833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.556041, + "p50": 0.584208, + "p95": 0.626334 + }, + "cpu_ms": { + "min": 0.555, + "p50": 0.583, + "p95": 0.626 + }, + "rss_peak_mb": 158.375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.584208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.060792, + "p50": 1.111084, + "p95": 1.295 + }, + "cpu_ms": { + "min": 1.061, + "p50": 1.111, + "p95": 1.262 + }, + "rss_peak_mb": 158.453125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.111084, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.936208, + "p50": 0.991792, + "p95": 1.068 + }, + "cpu_ms": { + "min": 0.937, + "p50": 0.992, + "p95": 1.068 + }, + "rss_peak_mb": 158.453125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.991792, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.123708, + "p50": 1.205125, + "p95": 1.325584 + }, + "cpu_ms": { + "min": 1.124, + "p50": 1.205, + "p95": 1.325 + }, + "rss_peak_mb": 158.453125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.205125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.582458, + "p50": 0.599958, + "p95": 0.708084 + }, + "cpu_ms": { + "min": 0.582, + "p50": 0.6, + "p95": 0.701 + }, + "rss_peak_mb": 158.453125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.599958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.060583, + "p50": 1.170791, + "p95": 1.284208 + }, + "cpu_ms": { + "min": 1.06, + "p50": 1.163, + "p95": 1.279 + }, + "rss_peak_mb": 158.484375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.170791, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.112375, + "p50": 1.201292, + "p95": 1.330125 + }, + "cpu_ms": { + "min": 1.112, + "p50": 1.202, + "p95": 1.329 + }, + "rss_peak_mb": 158.578125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.201292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.313584, + "p50": 1.414917, + "p95": 1.614542 + }, + "cpu_ms": { + "min": 1.314, + "p50": 1.414, + "p95": 1.61 + }, + "rss_peak_mb": 158.640625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.414917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.638209, + "p50": 0.689125, + "p95": 0.796708 + }, + "cpu_ms": { + "min": 0.639, + "p50": 0.689, + "p95": 0.797 + }, + "rss_peak_mb": 158.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.689125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.089291, + "p50": 1.112667, + "p95": 1.199625 + }, + "cpu_ms": { + "min": 1.09, + "p50": 1.113, + "p95": 1.199 + }, + "rss_peak_mb": 158.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.112667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.655125, + "p50": 1.740959, + "p95": 1.971416 + }, + "cpu_ms": { + "min": 1.655, + "p50": 1.741, + "p95": 1.972 + }, + "rss_peak_mb": 159.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.740959, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 2.065709, + "p50": 2.120083, + "p95": 2.619666 + }, + "cpu_ms": { + "min": 2.066, + "p50": 2.12, + "p95": 2.615 + }, + "rss_peak_mb": 159.34375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.120083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.93875, + "p50": 1.016709, + "p95": 1.142708 + }, + "cpu_ms": { + "min": 0.939, + "p50": 1.016, + "p95": 1.143 + }, + "rss_peak_mb": 159.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.016709, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.371625, + "p50": 1.471167, + "p95": 1.747375 + }, + "cpu_ms": { + "min": 1.371, + "p50": 1.471, + "p95": 1.747 + }, + "rss_peak_mb": 159.75, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.471167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.847042, + "p50": 0.981875, + "p95": 1.158292 + }, + "cpu_ms": { + "min": 0.847, + "p50": 0.975, + "p95": 1.151 + }, + "rss_peak_mb": 159.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.981875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.076875, + "p50": 1.133417, + "p95": 1.252917 + }, + "cpu_ms": { + "min": 1.076, + "p50": 1.133, + "p95": 1.248 + }, + "rss_peak_mb": 159.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.133417, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.521334, + "p50": 0.551917, + "p95": 0.633375 + }, + "cpu_ms": { + "min": 0.522, + "p50": 0.551, + "p95": 0.633 + }, + "rss_peak_mb": 159.90625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.551917, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.027209, + "p50": 1.096833, + "p95": 1.278417 + }, + "cpu_ms": { + "min": 1.027, + "p50": 1.097, + "p95": 1.279 + }, + "rss_peak_mb": 159.984375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.096833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.213417, + "p50": 1.248375, + "p95": 1.472875 + }, + "cpu_ms": { + "min": 1.213, + "p50": 1.248, + "p95": 1.472 + }, + "rss_peak_mb": 160.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.248375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.572167, + "p50": 1.651042, + "p95": 2.054625 + }, + "cpu_ms": { + "min": 1.572, + "p50": 1.652, + "p95": 2.054 + }, + "rss_peak_mb": 160.15625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.651042, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.485875, + "p50": 0.519458, + "p95": 0.568917 + }, + "cpu_ms": { + "min": 0.486, + "p50": 0.519, + "p95": 0.568 + }, + "rss_peak_mb": 160.21875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.519458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.179459, + "p50": 1.24825, + "p95": 1.430125 + }, + "cpu_ms": { + "min": 1.179, + "p50": 1.248, + "p95": 1.43 + }, + "rss_peak_mb": 160.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.24825, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.107625, + "p50": 1.199125, + "p95": 1.312625 + }, + "cpu_ms": { + "min": 1.108, + "p50": 1.198, + "p95": 1.313 + }, + "rss_peak_mb": 160.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.199125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.242709, + "p50": 1.315958, + "p95": 1.524458 + }, + "cpu_ms": { + "min": 1.243, + "p50": 1.317, + "p95": 1.519 + }, + "rss_peak_mb": 160.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.315958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.774208, + "p50": 0.803458, + "p95": 0.908334 + }, + "cpu_ms": { + "min": 0.775, + "p50": 0.803, + "p95": 0.909 + }, + "rss_peak_mb": 160.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.803458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.10825, + "p50": 1.14775, + "p95": 1.332458 + }, + "cpu_ms": { + "min": 1.108, + "p50": 1.148, + "p95": 1.332 + }, + "rss_peak_mb": 160.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.14775, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.319833, + "p50": 1.37525, + "p95": 1.59225 + }, + "cpu_ms": { + "min": 1.32, + "p50": 1.375, + "p95": 1.587 + }, + "rss_peak_mb": 160.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.37525, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.577, + "p50": 1.6325, + "p95": 1.754834 + }, + "cpu_ms": { + "min": 1.577, + "p50": 1.632, + "p95": 1.755 + }, + "rss_peak_mb": 160.6875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.6325, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.984708, + "p50": 1.0115, + "p95": 1.083625 + }, + "cpu_ms": { + "min": 0.985, + "p50": 1.011, + "p95": 1.085 + }, + "rss_peak_mb": 161.203125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.0115, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.19725, + "p50": 1.26375, + "p95": 1.3585 + }, + "cpu_ms": { + "min": 1.198, + "p50": 1.264, + "p95": 1.359 + }, + "rss_peak_mb": 161.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.26375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.147417, + "p50": 1.205167, + "p95": 1.412333 + }, + "cpu_ms": { + "min": 1.147, + "p50": 1.206, + "p95": 1.413 + }, + "rss_peak_mb": 161.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.205167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.135, + "p50": 1.183125, + "p95": 1.233916 + }, + "cpu_ms": { + "min": 1.135, + "p50": 1.183, + "p95": 1.234 + }, + "rss_peak_mb": 161.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.183125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.574875, + "p50": 0.593875, + "p95": 0.653625 + }, + "cpu_ms": { + "min": 0.575, + "p50": 0.594, + "p95": 0.654 + }, + "rss_peak_mb": 161.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.593875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.066959, + "p50": 1.135, + "p95": 1.253959 + }, + "cpu_ms": { + "min": 1.067, + "p50": 1.135, + "p95": 1.254 + }, + "rss_peak_mb": 161.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.135, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.125292, + "p50": 1.154708, + "p95": 1.194334 + }, + "cpu_ms": { + "min": 1.125, + "p50": 1.154, + "p95": 1.194 + }, + "rss_peak_mb": 161.9375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.154708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.153333, + "p50": 1.212791, + "p95": 1.276 + }, + "cpu_ms": { + "min": 1.153, + "p50": 1.212, + "p95": 1.276 + }, + "rss_peak_mb": 161.9375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.212791, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.121791, + "p50": 1.148334, + "p95": 1.215959 + }, + "cpu_ms": { + "min": 1.121, + "p50": 1.149, + "p95": 1.217 + }, + "rss_peak_mb": 161.96875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.148334, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.099625, + "p50": 1.139875, + "p95": 1.180375 + }, + "cpu_ms": { + "min": 1.1, + "p50": 1.14, + "p95": 1.181 + }, + "rss_peak_mb": 162.015625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.139875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.055, + "p50": 1.105667, + "p95": 1.15425 + }, + "cpu_ms": { + "min": 1.056, + "p50": 1.106, + "p95": 1.155 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.105667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.487208, + "p50": 1.578667, + "p95": 1.727583 + }, + "cpu_ms": { + "min": 1.487, + "p50": 1.571, + "p95": 1.714 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.578667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.854625, + "p50": 0.870959, + "p95": 0.906041 + }, + "cpu_ms": { + "min": 0.855, + "p50": 0.871, + "p95": 0.906 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.870959, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.383167, + "p50": 1.419292, + "p95": 1.576375 + }, + "cpu_ms": { + "min": 1.383, + "p50": 1.419, + "p95": 1.576 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.419292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.769208, + "p50": 0.825083, + "p95": 0.84975 + }, + "cpu_ms": { + "min": 0.769, + "p50": 0.825, + "p95": 0.85 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.825083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.049708, + "p50": 1.090791, + "p95": 1.159458 + }, + "cpu_ms": { + "min": 1.05, + "p50": 1.09, + "p95": 1.159 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.090791, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.444708, + "p50": 0.481084, + "p95": 0.516584 + }, + "cpu_ms": { + "min": 0.445, + "p50": 0.481, + "p95": 0.517 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.481084, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.023625, + "p50": 1.055458, + "p95": 1.123208 + }, + "cpu_ms": { + "min": 1.024, + "p50": 1.055, + "p95": 1.123 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.055458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.009667, + "p50": 1.063959, + "p95": 1.111875 + }, + "cpu_ms": { + "min": 1.01, + "p50": 1.064, + "p95": 1.112 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.063959, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.27425, + "p50": 1.315, + "p95": 1.36325 + }, + "cpu_ms": { + "min": 1.275, + "p50": 1.315, + "p95": 1.362 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.315, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.126625, + "p50": 1.149, + "p95": 1.202 + }, + "cpu_ms": { + "min": 1.127, + "p50": 1.149, + "p95": 1.202 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.149, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.209458, + "p50": 1.251625, + "p95": 1.303833 + }, + "cpu_ms": { + "min": 1.209, + "p50": 1.251, + "p95": 1.303 + }, + "rss_peak_mb": 163.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.251625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.274083, + "p50": 1.302292, + "p95": 1.343583 + }, + "cpu_ms": { + "min": 1.275, + "p50": 1.303, + "p95": 1.344 + }, + "rss_peak_mb": 163.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.302292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.786458, + "p50": 1.834, + "p95": 2.272708 + }, + "cpu_ms": { + "min": 1.786, + "p50": 1.834, + "p95": 2.273 + }, + "rss_peak_mb": 163.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.834, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.652542, + "p50": 0.674875, + "p95": 0.71875 + }, + "cpu_ms": { + "min": 0.653, + "p50": 0.676, + "p95": 0.72 + }, + "rss_peak_mb": 163.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.674875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.2825, + "p50": 1.317083, + "p95": 1.373167 + }, + "cpu_ms": { + "min": 1.282, + "p50": 1.318, + "p95": 1.373 + }, + "rss_peak_mb": 163.84375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.317083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.034625, + "p50": 1.080917, + "p95": 1.107375 + }, + "cpu_ms": { + "min": 1.034, + "p50": 1.081, + "p95": 1.107 + }, + "rss_peak_mb": 163.890625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.080917, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.293541, + "p50": 1.330041, + "p95": 1.367375 + }, + "cpu_ms": { + "min": 1.293, + "p50": 1.33, + "p95": 1.367 + }, + "rss_peak_mb": 163.890625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.330041, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.450416, + "p50": 0.478083, + "p95": 0.579334 + }, + "cpu_ms": { + "min": 0.45, + "p50": 0.478, + "p95": 0.579 + }, + "rss_peak_mb": 163.890625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.478083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.0795, + "p50": 1.120167, + "p95": 1.222875 + }, + "cpu_ms": { + "min": 1.08, + "p50": 1.12, + "p95": 1.224 + }, + "rss_peak_mb": 163.90625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.120167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.374833, + "p50": 1.412958, + "p95": 1.467584 + }, + "cpu_ms": { + "min": 1.375, + "p50": 1.413, + "p95": 1.467 + }, + "rss_peak_mb": 164.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.412958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.053375, + "p50": 1.09275, + "p95": 1.129167 + }, + "cpu_ms": { + "min": 1.054, + "p50": 1.093, + "p95": 1.129 + }, + "rss_peak_mb": 164.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.09275, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.490416, + "p50": 0.525625, + "p95": 0.561917 + }, + "cpu_ms": { + "min": 0.49, + "p50": 0.526, + "p95": 0.562 + }, + "rss_peak_mb": 164.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.525625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.052083, + "p50": 1.099959, + "p95": 1.241709 + }, + "cpu_ms": { + "min": 1.051, + "p50": 1.1, + "p95": 1.233 + }, + "rss_peak_mb": 164.3125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.099959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/results-2026-10-02/perf/history.jsonl b/results-2026-10-02/perf/history.jsonl new file mode 100644 index 0000000..eb06c33 --- /dev/null +++ b/results-2026-10-02/perf/history.jsonl @@ -0,0 +1 @@ +{"run_date": "2026-10-02T08:33:41.795781+00:00", "commit": null, "profile": "xlsx", "config": {"warmup": 3, "iters": 25, "iteration_policy": "fixed", "breakdown": false}, "p50_wall_ms": {"openpyxl": {"cell_values": {"read_p50": 1.257625, "write_p50": 1.21875}, "formulas": {"read_p50": 1.105625, "write_p50": 1.345334}, "text_formatting": {"read_p50": 1.672375, "write_p50": 1.789042}, "background_colors": {"read_p50": 0.982292, "write_p50": 1.197167}, "number_formats": {"read_p50": 1.008583, "write_p50": 1.1675}, "alignment": {"read_p50": 1.176833, "write_p50": 1.3235}, "borders": {"read_p50": 1.679375, "write_p50": 2.063291}, "dimensions": {"read_p50": 0.9385, "write_p50": 1.241542}, "multiple_sheets": {"read_p50": 1.311708, "write_p50": 1.736125}, "merged_cells": {"read_p50": 1.191958, "write_p50": 1.284958}, "conditional_formatting": {"read_p50": 1.347416, "write_p50": 1.591708}, "data_validation": {"read_p50": 1.1965, "write_p50": 1.190167}, "hyperlinks": {"read_p50": 1.140916, "write_p50": 1.175125}, "images": {"read_p50": 1.096208, "write_p50": 1.654542}, "pivot_tables": {"read_p50": 0.805583, "write_p50": 1.076792}, "comments": {"read_p50": 1.0675, "write_p50": 1.345458}, "freeze_panes": {"read_p50": 1.33325, "write_p50": 1.846916}, "named_ranges": {"read_p50": 1.08575, "write_p50": 1.367875}, "tables": {"read_p50": 1.395542, "write_p50": 1.082416}}, "xlsxwriter": {"cell_values": {"read_p50": null, "write_p50": 1.594916}, "formulas": {"read_p50": null, "write_p50": 1.529417}, "text_formatting": {"read_p50": null, "write_p50": 1.820959}, "background_colors": {"read_p50": null, "write_p50": 1.568208}, "number_formats": {"read_p50": null, "write_p50": 1.390916}, "alignment": {"read_p50": null, "write_p50": 1.579542}, "borders": {"read_p50": null, "write_p50": 2.010917}, "dimensions": {"read_p50": null, "write_p50": 1.349833}, "multiple_sheets": {"read_p50": null, "write_p50": 1.951084}, "merged_cells": {"read_p50": null, "write_p50": 1.494667}, "conditional_formatting": {"read_p50": null, "write_p50": 1.615125}, "data_validation": {"read_p50": null, "write_p50": 1.410667}, "hyperlinks": {"read_p50": null, "write_p50": 1.679125}, "images": {"read_p50": null, "write_p50": 2.319667}, "pivot_tables": {"read_p50": null, "write_p50": 1.307375}, "comments": {"read_p50": null, "write_p50": 1.765709}, "freeze_panes": {"read_p50": null, "write_p50": 1.751208}, "named_ranges": {"read_p50": null, "write_p50": 1.652041}, "tables": {"read_p50": null, "write_p50": 1.331208}}, "python-calamine": {"cell_values": {"read_p50": 0.616458, "write_p50": null}, "formulas": {"read_p50": 0.122375, "write_p50": null}, "text_formatting": {"read_p50": 0.071958, "write_p50": null}, "background_colors": {"read_p50": 0.05325, "write_p50": null}, "number_formats": {"read_p50": 0.055083, "write_p50": null}, "alignment": {"read_p50": 0.048292, "write_p50": null}, "borders": {"read_p50": 0.060375, "write_p50": null}, "dimensions": {"read_p50": 0.053, "write_p50": null}, "multiple_sheets": {"read_p50": 0.056834, "write_p50": null}, "merged_cells": {"read_p50": 0.053292, "write_p50": null}, "conditional_formatting": {"read_p50": 0.047625, "write_p50": null}, "data_validation": {"read_p50": 0.046334, "write_p50": null}, "hyperlinks": {"read_p50": 0.046583, "write_p50": null}, "images": {"read_p50": 0.04825, "write_p50": null}, "pivot_tables": {"read_p50": 0.049125, "write_p50": null}, "comments": {"read_p50": 0.054667, "write_p50": null}, "freeze_panes": {"read_p50": 0.04825, "write_p50": null}, "named_ranges": {"read_p50": 0.045292, "write_p50": null}, "tables": {"read_p50": 0.049042, "write_p50": null}}, "wolfxl": {"cell_values": {"read_p50": 0.661167, "write_p50": 1.184333}, "formulas": {"read_p50": 0.571292, "write_p50": 1.1715}, "text_formatting": {"read_p50": 0.835667, "write_p50": 1.218959}, "background_colors": {"read_p50": 0.579792, "write_p50": 1.123583}, "number_formats": {"read_p50": 0.590708, "write_p50": 1.083958}, "alignment": {"read_p50": 0.650375, "write_p50": 1.098958}, "borders": {"read_p50": 0.977166, "write_p50": 1.402292}, "dimensions": {"read_p50": 0.524125, "write_p50": 1.038792}, "multiple_sheets": {"read_p50": 0.536333, "write_p50": 1.300917}, "merged_cells": {"read_p50": 0.795292, "write_p50": 1.104542}, "conditional_formatting": {"read_p50": 0.98925, "write_p50": 1.223458}, "data_validation": {"read_p50": 0.577458, "write_p50": 1.075375}, "hyperlinks": {"read_p50": 1.115083, "write_p50": 1.13}, "images": {"read_p50": 0.846209, "write_p50": 1.423792}, "pivot_tables": {"read_p50": 0.466417, "write_p50": 1.02975}, "comments": {"read_p50": 1.106709, "write_p50": 1.20525}, "freeze_panes": {"read_p50": 0.665333, "write_p50": 1.304375}, "named_ranges": {"read_p50": 0.470875, "write_p50": 1.127291}, "tables": {"read_p50": 0.505292, "write_p50": 1.037584}}, "pylightxl": {"cell_values": {"read_p50": 1.26225, "write_p50": null}, "formulas": {"read_p50": 1.115709, "write_p50": 0.257708}, "text_formatting": {"read_p50": 1.420541, "write_p50": null}, "background_colors": {"read_p50": 0.898208, "write_p50": null}, "number_formats": {"read_p50": 0.93225, "write_p50": null}, "alignment": {"read_p50": null, "write_p50": null}, "borders": {"read_p50": null, "write_p50": null}, "dimensions": {"read_p50": 0.86775, "write_p50": null}, "multiple_sheets": {"read_p50": 1.287458, "write_p50": 0.32325}, "merged_cells": {"read_p50": 0.928667, "write_p50": null}, "conditional_formatting": {"read_p50": null, "write_p50": null}, "data_validation": {"read_p50": null, "write_p50": null}, "hyperlinks": {"read_p50": null, "write_p50": null}, "images": {"read_p50": null, "write_p50": null}, "pivot_tables": {"read_p50": 0.765958, "write_p50": 0.200625}, "comments": {"read_p50": 1.075667, "write_p50": null}, "freeze_panes": {"read_p50": null, "write_p50": null}, "named_ranges": {"read_p50": null, "write_p50": 0.225625}, "tables": {"read_p50": null, "write_p50": 0.203292}}, "xlrd": {"cell_values": {"read_p50": null, "write_p50": null}, "formulas": {"read_p50": null, "write_p50": null}, "text_formatting": {"read_p50": null, "write_p50": null}, "background_colors": {"read_p50": null, "write_p50": null}, "number_formats": {"read_p50": null, "write_p50": null}, "alignment": {"read_p50": null, "write_p50": null}, "borders": {"read_p50": null, "write_p50": null}, "dimensions": {"read_p50": null, "write_p50": null}, "multiple_sheets": {"read_p50": null, "write_p50": null}, "merged_cells": {"read_p50": null, "write_p50": null}, "conditional_formatting": {"read_p50": null, "write_p50": null}, "data_validation": {"read_p50": null, "write_p50": null}, "hyperlinks": {"read_p50": null, "write_p50": null}, "images": {"read_p50": null, "write_p50": null}, "pivot_tables": {"read_p50": null, "write_p50": null}, "comments": {"read_p50": null, "write_p50": null}, "freeze_panes": {"read_p50": null, "write_p50": null}, "named_ranges": {"read_p50": null, "write_p50": null}, "tables": {"read_p50": null, "write_p50": null}}, "pyexcel": {"cell_values": {"read_p50": 1.404875, "write_p50": null}, "formulas": {"read_p50": 1.194125, "write_p50": 1.386458}, "text_formatting": {"read_p50": 1.732375, "write_p50": null}, "background_colors": {"read_p50": 1.041708, "write_p50": null}, "number_formats": {"read_p50": 1.06275, "write_p50": null}, "alignment": {"read_p50": 1.225875, "write_p50": null}, "borders": {"read_p50": 1.759708, "write_p50": null}, "dimensions": {"read_p50": 1.014125, "write_p50": null}, "multiple_sheets": {"read_p50": 1.649875, "write_p50": 2.307}, "merged_cells": {"read_p50": 1.266084, "write_p50": null}, "conditional_formatting": {"read_p50": 1.453541, "write_p50": null}, "data_validation": {"read_p50": 1.309583, "write_p50": null}, "hyperlinks": {"read_p50": 1.261625, "write_p50": null}, "images": {"read_p50": 1.16775, "write_p50": null}, "pivot_tables": {"read_p50": 0.876583, "write_p50": 1.081083}, "comments": {"read_p50": 1.132833, "write_p50": null}, "freeze_panes": {"read_p50": 1.448625, "write_p50": null}, "named_ranges": {"read_p50": 1.19925, "write_p50": 1.389667}, "tables": {"read_p50": 1.720291, "write_p50": 1.110916}}, "xlwt": {"cell_values": {"read_p50": null, "write_p50": 0.22425}, "formulas": {"read_p50": null, "write_p50": 0.256042}, "text_formatting": {"read_p50": null, "write_p50": 0.335542}, "background_colors": {"read_p50": null, "write_p50": 0.181625}, "number_formats": {"read_p50": null, "write_p50": 0.186584}, "alignment": {"read_p50": null, "write_p50": 0.215167}, "borders": {"read_p50": null, "write_p50": 0.394541}, "dimensions": {"read_p50": null, "write_p50": 0.161708}, "multiple_sheets": {"read_p50": null, "write_p50": 0.176209}, "merged_cells": {"read_p50": null, "write_p50": 0.178625}, "conditional_formatting": {"read_p50": null, "write_p50": null}, "data_validation": {"read_p50": null, "write_p50": null}, "hyperlinks": {"read_p50": null, "write_p50": null}, "images": {"read_p50": null, "write_p50": null}, "pivot_tables": {"read_p50": null, "write_p50": 0.123959}, "comments": {"read_p50": null, "write_p50": null}, "freeze_panes": {"read_p50": null, "write_p50": 0.182833}, "named_ranges": {"read_p50": null, "write_p50": 0.148959}, "tables": {"read_p50": null, "write_p50": 0.129458}}, "pandas": {"cell_values": {"read_p50": 1.707042, "write_p50": 1.47725}, "formulas": {"read_p50": 1.519666, "write_p50": 1.596541}, "text_formatting": {"read_p50": 1.939375, "write_p50": 1.438709}, "background_colors": {"read_p50": 1.197, "write_p50": 1.302292}, "number_formats": {"read_p50": 1.230667, "write_p50": 1.316875}, "alignment": {"read_p50": 1.416875, "write_p50": 1.352916}, "borders": {"read_p50": 2.001834, "write_p50": 1.484917}, "dimensions": {"read_p50": 1.462792, "write_p50": 1.289208}, "multiple_sheets": {"read_p50": 1.763834, "write_p50": 2.018}, "merged_cells": {"read_p50": 1.258209, "write_p50": 1.351917}, "conditional_formatting": {"read_p50": 1.708541, "write_p50": 1.43175}, "data_validation": {"read_p50": 1.61275, "write_p50": 1.181125}, "hyperlinks": {"read_p50": 1.510167, "write_p50": 1.190625}, "images": {"read_p50": 1.106083, "write_p50": 1.168583}, "pivot_tables": {"read_p50": 1.031375, "write_p50": 1.18425}, "comments": {"read_p50": 1.172459, "write_p50": 1.216375}, "freeze_panes": {"read_p50": 1.732584, "write_p50": 2.000125}, "named_ranges": {"read_p50": 1.450958, "write_p50": 1.457959}, "tables": {"read_p50": 1.607792, "write_p50": 1.196375}}, "xlsxwriter-constmem": {"cell_values": {"read_p50": null, "write_p50": 1.587125}, "formulas": {"read_p50": null, "write_p50": 1.707}, "text_formatting": {"read_p50": null, "write_p50": 1.919833}, "background_colors": {"read_p50": null, "write_p50": 1.548416}, "number_formats": {"read_p50": null, "write_p50": 1.737083}, "alignment": {"read_p50": null, "write_p50": 1.626834}, "borders": {"read_p50": null, "write_p50": 1.953875}, "dimensions": {"read_p50": null, "write_p50": 1.640792}, "multiple_sheets": {"read_p50": null, "write_p50": 2.003416}, "merged_cells": {"read_p50": null, "write_p50": 1.486208}, "conditional_formatting": {"read_p50": null, "write_p50": 1.719}, "data_validation": {"read_p50": null, "write_p50": 1.460042}, "hyperlinks": {"read_p50": null, "write_p50": 1.683584}, "images": {"read_p50": null, "write_p50": 1.391583}, "pivot_tables": {"read_p50": null, "write_p50": 1.390875}, "comments": {"read_p50": null, "write_p50": 1.359292}, "freeze_panes": {"read_p50": null, "write_p50": 2.007459}, "named_ranges": {"read_p50": null, "write_p50": 1.573417}, "tables": {"read_p50": null, "write_p50": 1.378416}}, "openpyxl-readonly": {"cell_values": {"read_p50": 5.687583, "write_p50": null}, "formulas": {"read_p50": 1.434709, "write_p50": null}, "text_formatting": {"read_p50": 1.417125, "write_p50": null}, "background_colors": {"read_p50": 0.83675, "write_p50": null}, "number_formats": {"read_p50": 0.857083, "write_p50": null}, "alignment": {"read_p50": 0.924792, "write_p50": null}, "borders": {"read_p50": 1.273042, "write_p50": null}, "dimensions": {"read_p50": 0.836541, "write_p50": null}, "multiple_sheets": {"read_p50": 0.972958, "write_p50": null}, "merged_cells": {"read_p50": 0.862959, "write_p50": null}, "conditional_formatting": {"read_p50": 0.909042, "write_p50": null}, "data_validation": {"read_p50": 0.852375, "write_p50": null}, "hyperlinks": {"read_p50": 0.888458, "write_p50": null}, "images": {"read_p50": 0.769667, "write_p50": null}, "pivot_tables": {"read_p50": 0.690291, "write_p50": null}, "comments": {"read_p50": 0.840167, "write_p50": null}, "freeze_panes": {"read_p50": 0.947791, "write_p50": null}, "named_ranges": {"read_p50": 0.848459, "write_p50": null}, "tables": {"read_p50": 0.902875, "write_p50": null}}, "polars": {"cell_values": {"read_p50": 0.316292, "write_p50": null}, "formulas": {"read_p50": 0.406083, "write_p50": null}, "text_formatting": {"read_p50": 0.250208, "write_p50": null}, "background_colors": {"read_p50": 0.236125, "write_p50": null}, "number_formats": {"read_p50": 0.235083, "write_p50": null}, "alignment": {"read_p50": 0.224375, "write_p50": null}, "borders": {"read_p50": 0.2645, "write_p50": null}, "dimensions": {"read_p50": 0.357375, "write_p50": null}, "multiple_sheets": {"read_p50": 0.521166, "write_p50": null}, "merged_cells": {"read_p50": 0.229292, "write_p50": null}, "conditional_formatting": {"read_p50": 0.358292, "write_p50": null}, "data_validation": {"read_p50": 0.511333, "write_p50": null}, "hyperlinks": {"read_p50": 0.357083, "write_p50": null}, "images": {"read_p50": 0.215833, "write_p50": null}, "pivot_tables": {"read_p50": 0.202167, "write_p50": null}, "comments": {"read_p50": 0.22575, "write_p50": null}, "freeze_panes": {"read_p50": 0.439542, "write_p50": null}, "named_ranges": {"read_p50": 0.407625, "write_p50": null}, "tables": {"read_p50": 0.370833, "write_p50": null}}, "tablib": {"cell_values": {"read_p50": 1.372458, "write_p50": 1.304959}, "formulas": {"read_p50": 1.158542, "write_p50": 1.367083}, "text_formatting": {"read_p50": 1.733708, "write_p50": 1.254459}, "background_colors": {"read_p50": 0.993458, "write_p50": 1.106792}, "number_formats": {"read_p50": 1.006291, "write_p50": 1.120667}, "alignment": {"read_p50": 1.208, "write_p50": 1.159}, "borders": {"read_p50": 1.759125, "write_p50": 1.323958}, "dimensions": {"read_p50": 1.031292, "write_p50": 1.239583}, "multiple_sheets": {"read_p50": 1.3145, "write_p50": 1.713333}, "merged_cells": {"read_p50": 1.04675, "write_p50": 1.12825}, "conditional_formatting": {"read_p50": 1.378667, "write_p50": 1.322791}, "data_validation": {"read_p50": 1.322833, "write_p50": 1.054917}, "hyperlinks": {"read_p50": 1.206125, "write_p50": 1.078125}, "images": {"read_p50": 0.92575, "write_p50": 1.056708}, "pivot_tables": {"read_p50": 0.821125, "write_p50": 1.0535}, "comments": {"read_p50": 0.968875, "write_p50": 1.070833}, "freeze_panes": {"read_p50": 1.360458, "write_p50": 1.808959}, "named_ranges": {"read_p50": 1.150333, "write_p50": 1.332375}, "tables": {"read_p50": 1.331125, "write_p50": 1.082375}}}} diff --git a/results-2026-10-02/perf/matrix.csv b/results-2026-10-02/perf/matrix.csv new file mode 100644 index 0000000..1b51f13 --- /dev/null +++ b/results-2026-10-02/perf/matrix.csv @@ -0,0 +1,248 @@ +library,feature,read_p50_wall_ms,read_p95_wall_ms,read_op_count,read_op_unit,read_p50_units_per_sec,write_p50_wall_ms,write_p95_wall_ms,write_op_count,write_op_unit,write_p50_units_per_sec,read_tail_ratio,write_tail_ratio,confidence_note,regression_status +openpyxl,cell_values,1.257625,1.545292,,,,1.21875,1.288042,,,,0.2287,0.0569,high,no_history +xlsxwriter,cell_values,,,,,,1.594916,2.034042,,,,,0.2753,high,no_history +python-calamine,cell_values,0.616458,0.626333,,,,,,,,,0.016,,ok,no_history +wolfxl,cell_values,0.661167,0.73025,,,,1.184333,1.27775,,,,0.1045,0.0789,ok,no_history +pylightxl,cell_values,1.26225,1.280667,,,,,,,,,0.0146,,ok,no_history +xlrd,cell_values,,,,,,,,,,,,,ok,no_history +pyexcel,cell_values,1.404875,1.437583,,,,,,,,,0.0233,,ok,no_history +xlwt,cell_values,,,,,,0.22425,0.276959,,,,,0.235,high,no_history +pandas,cell_values,1.707042,1.824125,,,,1.47725,1.548875,,,,0.0686,0.0485,ok,no_history +xlsxwriter-constmem,cell_values,,,,,,1.587125,1.99525,,,,,0.2571,high,no_history +openpyxl-readonly,cell_values,5.687583,5.941375,,,,,,,,,0.0446,,ok,no_history +polars,cell_values,0.316292,0.423584,,,,,,,,,0.3392,,high,no_history +tablib,cell_values,1.372458,1.399041,,,,1.304959,1.375375,,,,0.0194,0.054,ok,no_history +openpyxl,formulas,1.105625,1.1325,,,,1.345334,1.407083,,,,0.0243,0.0459,ok,no_history +xlsxwriter,formulas,,,,,,1.529417,1.992916,,,,,0.3031,high,no_history +python-calamine,formulas,0.122375,0.124458,,,,,,,,,0.017,,ok,no_history +wolfxl,formulas,0.571292,0.631542,,,,1.1715,1.327666,,,,0.1055,0.1333,ok,no_history +pylightxl,formulas,1.115709,1.141458,,,,0.257708,0.287459,,,,0.0231,0.1154,ok,no_history +xlrd,formulas,,,,,,,,,,,,,ok,no_history +pyexcel,formulas,1.194125,1.237792,,,,1.386458,1.465583,,,,0.0366,0.0571,ok,no_history +xlwt,formulas,,,,,,0.256042,0.338625,,,,,0.3225,high,no_history +pandas,formulas,1.519666,1.54975,,,,1.596541,1.85925,,,,0.0198,0.1645,ok,no_history +xlsxwriter-constmem,formulas,,,,,,1.707,2.169792,,,,,0.2711,high,no_history +openpyxl-readonly,formulas,1.434709,1.670375,,,,,,,,,0.1643,,ok,no_history +polars,formulas,0.406083,0.537333,,,,,,,,,0.3232,,high,no_history +tablib,formulas,1.158542,1.186375,,,,1.367083,1.432666,,,,0.024,0.048,ok,no_history +openpyxl,text_formatting,1.672375,1.703791,,,,1.789042,1.852458,,,,0.0188,0.0354,ok,no_history +xlsxwriter,text_formatting,,,,,,1.820959,2.232625,,,,,0.2261,high,no_history +python-calamine,text_formatting,0.071958,0.079625,,,,,,,,,0.1065,,ok,no_history +wolfxl,text_formatting,0.835667,0.903125,,,,1.218959,1.296792,,,,0.0807,0.0639,ok,no_history +pylightxl,text_formatting,1.420541,1.46475,,,,,,,,,0.0311,,ok,no_history +xlrd,text_formatting,,,,,,,,,,,,,ok,no_history +pyexcel,text_formatting,1.732375,1.790833,,,,,,,,,0.0337,,ok,no_history +xlwt,text_formatting,,,,,,0.335542,0.627875,,,,,0.8712,high,no_history +pandas,text_formatting,1.939375,1.963875,,,,1.438709,1.538917,,,,0.0126,0.0697,ok,no_history +xlsxwriter-constmem,text_formatting,,,,,,1.919833,2.216458,,,,,0.1545,ok,no_history +openpyxl-readonly,text_formatting,1.417125,1.458,,,,,,,,,0.0288,,ok,no_history +polars,text_formatting,0.250208,0.297291,,,,,,,,,0.1882,,ok,no_history +tablib,text_formatting,1.733708,1.850916,,,,1.254459,1.318875,,,,0.0676,0.0513,ok,no_history +openpyxl,background_colors,0.982292,1.034458,,,,1.197167,1.245416,,,,0.0531,0.0403,ok,no_history +xlsxwriter,background_colors,,,,,,1.568208,1.973125,,,,,0.2582,high,no_history +python-calamine,background_colors,0.05325,0.056625,,,,,,,,,0.0634,,ok,no_history +wolfxl,background_colors,0.579792,0.646458,,,,1.123583,1.22925,,,,0.115,0.094,ok,no_history +pylightxl,background_colors,0.898208,0.914083,,,,,,,,,0.0177,,ok,no_history +xlrd,background_colors,,,,,,,,,,,,,ok,no_history +pyexcel,background_colors,1.041708,1.083167,,,,,,,,,0.0398,,ok,no_history +xlwt,background_colors,,,,,,0.181625,0.189792,,,,,0.045,ok,no_history +pandas,background_colors,1.197,1.3,,,,1.302292,1.363542,,,,0.086,0.047,ok,no_history +xlsxwriter-constmem,background_colors,,,,,,1.548416,1.969291,,,,,0.2718,high,no_history +openpyxl-readonly,background_colors,0.83675,0.871833,,,,,,,,,0.0419,,ok,no_history +polars,background_colors,0.236125,0.317709,,,,,,,,,0.3455,,high,no_history +tablib,background_colors,0.993458,1.017834,,,,1.106792,1.185833,,,,0.0245,0.0714,ok,no_history +openpyxl,number_formats,1.008583,1.060083,,,,1.1675,1.202458,,,,0.0511,0.0299,ok,no_history +xlsxwriter,number_formats,,,,,,1.390916,1.884959,,,,,0.3552,high,no_history +python-calamine,number_formats,0.055083,0.057417,,,,,,,,,0.0424,,ok,no_history +wolfxl,number_formats,0.590708,0.63375,,,,1.083958,1.337167,,,,0.0729,0.2336,high,no_history +pylightxl,number_formats,0.93225,0.949792,,,,,,,,,0.0188,,ok,no_history +xlrd,number_formats,,,,,,,,,,,,,ok,no_history +pyexcel,number_formats,1.06275,1.116333,,,,,,,,,0.0504,,ok,no_history +xlwt,number_formats,,,,,,0.186584,0.238,,,,,0.2756,high,no_history +pandas,number_formats,1.230667,1.279375,,,,1.316875,1.713,,,,0.0396,0.3008,high,no_history +xlsxwriter-constmem,number_formats,,,,,,1.737083,1.966667,,,,,0.1322,ok,no_history +openpyxl-readonly,number_formats,0.857083,0.8815,,,,,,,,,0.0285,,ok,no_history +polars,number_formats,0.235083,0.2885,,,,,,,,,0.2272,,high,no_history +tablib,number_formats,1.006291,1.113416,,,,1.120667,1.17,,,,0.1065,0.044,ok,no_history +openpyxl,alignment,1.176833,1.221875,,,,1.3235,1.396,,,,0.0383,0.0548,ok,no_history +xlsxwriter,alignment,,,,,,1.579542,1.854916,,,,,0.1743,ok,no_history +python-calamine,alignment,0.048292,0.050208,,,,,,,,,0.0397,,ok,no_history +wolfxl,alignment,0.650375,0.694792,,,,1.098958,1.182375,,,,0.0683,0.0759,ok,no_history +pylightxl,alignment,,,,,,,,,,,,,ok,no_history +xlrd,alignment,,,,,,,,,,,,,ok,no_history +pyexcel,alignment,1.225875,1.26825,,,,,,,,,0.0346,,ok,no_history +xlwt,alignment,,,,,,0.215167,0.232958,,,,,0.0827,ok,no_history +pandas,alignment,1.416875,1.542375,,,,1.352916,1.407209,,,,0.0886,0.0401,ok,no_history +xlsxwriter-constmem,alignment,,,,,,1.626834,1.990375,,,,,0.2235,high,no_history +openpyxl-readonly,alignment,0.924792,0.955334,,,,,,,,,0.033,,ok,no_history +polars,alignment,0.224375,0.274916,,,,,,,,,0.2253,,high,no_history +tablib,alignment,1.208,1.379708,,,,1.159,1.222583,,,,0.1421,0.0549,ok,no_history +openpyxl,borders,1.679375,1.80325,,,,2.063291,2.319584,,,,0.0738,0.1242,ok,no_history +xlsxwriter,borders,,,,,,2.010917,2.458209,,,,,0.2224,high,no_history +python-calamine,borders,0.060375,0.065333,,,,,,,,,0.0821,,ok,no_history +wolfxl,borders,0.977166,1.006125,,,,1.402292,1.497625,,,,0.0296,0.068,ok,no_history +pylightxl,borders,,,,,,,,,,,,,ok,no_history +xlrd,borders,,,,,,,,,,,,,ok,no_history +pyexcel,borders,1.759708,1.803584,,,,,,,,,0.0249,,ok,no_history +xlwt,borders,,,,,,0.394541,0.45075,,,,,0.1425,ok,no_history +pandas,borders,2.001834,2.273791,,,,1.484917,1.537333,,,,0.1359,0.0353,ok,no_history +xlsxwriter-constmem,borders,,,,,,1.953875,2.318375,,,,,0.1866,ok,no_history +openpyxl-readonly,borders,1.273042,1.314416,,,,,,,,,0.0325,,ok,no_history +polars,borders,0.2645,0.317208,,,,,,,,,0.1993,,ok,no_history +tablib,borders,1.759125,2.100958,,,,1.323958,1.47875,,,,0.1943,0.1169,ok,no_history +openpyxl,dimensions,0.9385,1.040417,,,,1.241542,1.296541,,,,0.1086,0.0443,ok,no_history +xlsxwriter,dimensions,,,,,,1.349833,1.851041,,,,,0.3713,high,no_history +python-calamine,dimensions,0.053,0.054583,,,,,,,,,0.0299,,ok,no_history +wolfxl,dimensions,0.524125,0.559042,,,,1.038792,1.1755,,,,0.0666,0.1316,ok,no_history +pylightxl,dimensions,0.86775,0.893083,,,,,,,,,0.0292,,ok,no_history +xlrd,dimensions,,,,,,,,,,,,,ok,no_history +pyexcel,dimensions,1.014125,1.054666,,,,,,,,,0.04,,ok,no_history +xlwt,dimensions,,,,,,0.161708,0.222,,,,,0.3728,high,no_history +pandas,dimensions,1.462792,1.632917,,,,1.289208,1.429709,,,,0.1163,0.109,ok,no_history +xlsxwriter-constmem,dimensions,,,,,,1.640792,2.237917,,,,,0.3639,high,no_history +openpyxl-readonly,dimensions,0.836541,0.927667,,,,,,,,,0.1089,,ok,no_history +polars,dimensions,0.357375,0.454542,,,,,,,,,0.2719,,high,no_history +tablib,dimensions,1.031292,1.181167,,,,1.239583,1.373958,,,,0.1453,0.1084,ok,no_history +openpyxl,multiple_sheets,1.311708,1.4105,,,,1.736125,1.925375,,,,0.0753,0.109,ok,no_history +xlsxwriter,multiple_sheets,,,,,,1.951084,2.414709,,,,,0.2376,high,no_history +python-calamine,multiple_sheets,0.056834,0.062,,,,,,,,,0.0909,,ok,no_history +wolfxl,multiple_sheets,0.536333,0.580625,,,,1.300917,1.496042,,,,0.0826,0.15,ok,no_history +pylightxl,multiple_sheets,1.287458,1.4425,,,,0.32325,0.379625,,,,0.1204,0.1744,ok,no_history +xlrd,multiple_sheets,,,,,,,,,,,,,ok,no_history +pyexcel,multiple_sheets,1.649875,2.731792,,,,2.307,2.692583,,,,0.6558,0.1671,high,no_history +xlwt,multiple_sheets,,,,,,0.176209,0.18475,,,,,0.0485,ok,no_history +pandas,multiple_sheets,1.763834,1.835708,,,,2.018,2.372875,,,,0.0407,0.1759,ok,no_history +xlsxwriter-constmem,multiple_sheets,,,,,,2.003416,2.45025,,,,,0.223,high,no_history +openpyxl-readonly,multiple_sheets,0.972958,1.006542,,,,,,,,,0.0345,,ok,no_history +polars,multiple_sheets,0.521166,0.685792,,,,,,,,,0.3159,,high,no_history +tablib,multiple_sheets,1.3145,1.3485,,,,1.713333,2.515416,,,,0.0259,0.4681,high,no_history +openpyxl,merged_cells,1.191958,1.228417,,,,1.284958,1.321875,,,,0.0306,0.0287,ok,no_history +xlsxwriter,merged_cells,,,,,,1.494667,2.036,,,,,0.3622,high,no_history +python-calamine,merged_cells,0.053292,0.059084,,,,,,,,,0.1087,,ok,no_history +wolfxl,merged_cells,0.795292,0.870791,,,,1.104542,1.372625,,,,0.0949,0.2427,high,no_history +pylightxl,merged_cells,0.928667,0.948375,,,,,,,,,0.0212,,ok,no_history +xlrd,merged_cells,,,,,,,,,,,,,ok,no_history +pyexcel,merged_cells,1.266084,1.30475,,,,,,,,,0.0305,,ok,no_history +xlwt,merged_cells,,,,,,0.178625,0.191125,,,,,0.07,ok,no_history +pandas,merged_cells,1.258209,1.283958,,,,1.351917,1.426833,,,,0.0205,0.0554,ok,no_history +xlsxwriter-constmem,merged_cells,,,,,,1.486208,1.942959,,,,,0.3073,high,no_history +openpyxl-readonly,merged_cells,0.862959,0.883875,,,,,,,,,0.0242,,ok,no_history +polars,merged_cells,0.229292,0.273958,,,,,,,,,0.1948,,ok,no_history +tablib,merged_cells,1.04675,1.061708,,,,1.12825,1.220834,,,,0.0143,0.0821,ok,no_history +openpyxl,conditional_formatting,1.347416,1.397334,,,,1.591708,1.761958,,,,0.037,0.107,ok,no_history +xlsxwriter,conditional_formatting,,,,,,1.615125,2.082625,,,,,0.2895,high,no_history +python-calamine,conditional_formatting,0.047625,0.052416,,,,,,,,,0.1006,,ok,no_history +wolfxl,conditional_formatting,0.98925,1.038125,,,,1.223458,1.276833,,,,0.0494,0.0436,ok,no_history +pylightxl,conditional_formatting,,,,,,,,,,,,,ok,no_history +xlrd,conditional_formatting,,,,,,,,,,,,,ok,no_history +pyexcel,conditional_formatting,1.453541,1.598542,,,,,,,,,0.0998,,ok,no_history +xlwt,conditional_formatting,,,,,,,,,,,,,ok,no_history +pandas,conditional_formatting,1.708541,1.728209,,,,1.43175,1.563375,,,,0.0115,0.0919,ok,no_history +xlsxwriter-constmem,conditional_formatting,,,,,,1.719,2.144291,,,,,0.2474,high,no_history +openpyxl-readonly,conditional_formatting,0.909042,0.952708,,,,,,,,,0.048,,ok,no_history +polars,conditional_formatting,0.358292,0.497667,,,,,,,,,0.389,,high,no_history +tablib,conditional_formatting,1.378667,1.410333,,,,1.322791,1.439459,,,,0.023,0.0882,ok,no_history +openpyxl,data_validation,1.1965,1.244166,,,,1.190167,1.341875,,,,0.0398,0.1275,ok,no_history +xlsxwriter,data_validation,,,,,,1.410667,1.769583,,,,,0.2544,high,no_history +python-calamine,data_validation,0.046334,0.051209,,,,,,,,,0.1052,,ok,no_history +wolfxl,data_validation,0.577458,0.637875,,,,1.075375,1.11375,,,,0.1046,0.0357,ok,no_history +pylightxl,data_validation,,,,,,,,,,,,,ok,no_history +xlrd,data_validation,,,,,,,,,,,,,ok,no_history +pyexcel,data_validation,1.309583,1.624542,,,,,,,,,0.2405,,high,no_history +xlwt,data_validation,,,,,,,,,,,,,ok,no_history +pandas,data_validation,1.61275,1.746666,,,,1.181125,1.254041,,,,0.083,0.0617,ok,no_history +xlsxwriter-constmem,data_validation,,,,,,1.460042,1.850458,,,,,0.2674,high,no_history +openpyxl-readonly,data_validation,0.852375,0.916875,,,,,,,,,0.0757,,ok,no_history +polars,data_validation,0.511333,0.690917,,,,,,,,,0.3512,,high,no_history +tablib,data_validation,1.322833,1.475083,,,,1.054917,1.1035,,,,0.1151,0.0461,ok,no_history +openpyxl,hyperlinks,1.140916,1.174708,,,,1.175125,1.206875,,,,0.0296,0.027,ok,no_history +xlsxwriter,hyperlinks,,,,,,1.679125,2.124042,,,,,0.265,high,no_history +python-calamine,hyperlinks,0.046583,0.04775,,,,,,,,,0.0251,,ok,no_history +wolfxl,hyperlinks,1.115083,1.17175,,,,1.13,1.281792,,,,0.0508,0.1343,ok,no_history +pylightxl,hyperlinks,,,,,,,,,,,,,ok,no_history +xlrd,hyperlinks,,,,,,,,,,,,,ok,no_history +pyexcel,hyperlinks,1.261625,1.351458,,,,,,,,,0.0712,,ok,no_history +xlwt,hyperlinks,,,,,,,,,,,,,ok,no_history +pandas,hyperlinks,1.510167,1.551833,,,,1.190625,1.31675,,,,0.0276,0.1059,ok,no_history +xlsxwriter-constmem,hyperlinks,,,,,,1.683584,1.8925,,,,,0.1241,ok,no_history +openpyxl-readonly,hyperlinks,0.888458,1.020583,,,,,,,,,0.1487,,ok,no_history +polars,hyperlinks,0.357083,0.477666,,,,,,,,,0.3377,,high,no_history +tablib,hyperlinks,1.206125,1.280458,,,,1.078125,1.149667,,,,0.0616,0.0664,ok,no_history +openpyxl,images,1.096208,1.167834,,,,1.654542,1.760167,,,,0.0653,0.0638,ok,no_history +xlsxwriter,images,,,,,,2.319667,2.80025,,,,,0.2072,high,no_history +python-calamine,images,0.04825,0.053417,,,,,,,,,0.1071,,ok,no_history +wolfxl,images,0.846209,0.900291,,,,1.423792,1.55475,,,,0.0639,0.092,ok,no_history +pylightxl,images,,,,,,,,,,,,,ok,no_history +xlrd,images,,,,,,,,,,,,,ok,no_history +pyexcel,images,1.16775,1.236459,,,,,,,,,0.0588,,ok,no_history +xlwt,images,,,,,,,,,,,,,ok,no_history +pandas,images,1.106083,1.145084,,,,1.168583,1.242,,,,0.0353,0.0628,ok,no_history +xlsxwriter-constmem,images,,,,,,1.391583,1.816625,,,,,0.3054,high,no_history +openpyxl-readonly,images,0.769667,0.811333,,,,,,,,,0.0541,,ok,no_history +polars,images,0.215833,0.273042,,,,,,,,,0.2651,,high,no_history +tablib,images,0.92575,0.946334,,,,1.056708,1.133958,,,,0.0222,0.0731,ok,no_history +openpyxl,pivot_tables,0.805583,0.840875,,,,1.076792,1.130875,,,,0.0438,0.0502,ok,no_history +xlsxwriter,pivot_tables,,,,,,1.307375,1.6915,,,,,0.2938,high,no_history +python-calamine,pivot_tables,0.049125,0.054292,,,,,,,,,0.1052,,ok,no_history +wolfxl,pivot_tables,0.466417,0.513625,,,,1.02975,1.118125,,,,0.1012,0.0858,ok,no_history +pylightxl,pivot_tables,0.765958,0.829084,,,,0.200625,0.210208,,,,0.0824,0.0478,ok,no_history +xlrd,pivot_tables,,,,,,,,,,,,,ok,no_history +pyexcel,pivot_tables,0.876583,0.922167,,,,1.081083,1.127292,,,,0.052,0.0427,ok,no_history +xlwt,pivot_tables,,,,,,0.123959,0.132083,,,,,0.0655,ok,no_history +pandas,pivot_tables,1.031375,1.07575,,,,1.18425,1.272167,,,,0.043,0.0742,ok,no_history +xlsxwriter-constmem,pivot_tables,,,,,,1.390875,1.908709,,,,,0.3723,high,no_history +openpyxl-readonly,pivot_tables,0.690291,0.750375,,,,,,,,,0.087,,ok,no_history +polars,pivot_tables,0.202167,0.251375,,,,,,,,,0.2434,,high,no_history +tablib,pivot_tables,0.821125,0.847833,,,,1.0535,1.115625,,,,0.0325,0.059,ok,no_history +openpyxl,comments,1.0675,1.086708,,,,1.345458,1.447666,,,,0.018,0.076,ok,no_history +xlsxwriter,comments,,,,,,1.765709,2.268625,,,,,0.2848,high,no_history +python-calamine,comments,0.054667,0.059209,,,,,,,,,0.0831,,ok,no_history +wolfxl,comments,1.106709,1.185583,,,,1.20525,1.270041,,,,0.0713,0.0538,ok,no_history +pylightxl,comments,1.075667,1.096416,,,,,,,,,0.0193,,ok,no_history +xlrd,comments,,,,,,,,,,,,,ok,no_history +pyexcel,comments,1.132833,1.274833,,,,,,,,,0.1253,,ok,no_history +xlwt,comments,,,,,,,,,,,,,ok,no_history +pandas,comments,1.172459,1.21775,,,,1.216375,1.282417,,,,0.0386,0.0543,ok,no_history +xlsxwriter-constmem,comments,,,,,,1.359292,1.622916,,,,,0.1939,ok,no_history +openpyxl-readonly,comments,0.840167,0.884291,,,,,,,,,0.0525,,ok,no_history +polars,comments,0.22575,0.270166,,,,,,,,,0.1967,,ok,no_history +tablib,comments,0.968875,1.017333,,,,1.070833,1.273916,,,,0.05,0.1896,ok,no_history +openpyxl,freeze_panes,1.33325,1.362125,,,,1.846916,2.033458,,,,0.0217,0.101,ok,no_history +xlsxwriter,freeze_panes,,,,,,1.751208,2.267084,,,,,0.2946,high,no_history +python-calamine,freeze_panes,0.04825,0.05375,,,,,,,,,0.114,,ok,no_history +wolfxl,freeze_panes,0.665333,0.706292,,,,1.304375,1.485667,,,,0.0616,0.139,ok,no_history +pylightxl,freeze_panes,,,,,,,,,,,,,ok,no_history +xlrd,freeze_panes,,,,,,,,,,,,,ok,no_history +pyexcel,freeze_panes,1.448625,1.519875,,,,,,,,,0.0492,,ok,no_history +xlwt,freeze_panes,,,,,,0.182833,0.197917,,,,,0.0825,ok,no_history +pandas,freeze_panes,1.732584,1.877458,,,,2.000125,2.277333,,,,0.0836,0.1386,ok,no_history +xlsxwriter-constmem,freeze_panes,,,,,,2.007459,2.604708,,,,,0.2975,high,no_history +openpyxl-readonly,freeze_panes,0.947791,0.993958,,,,,,,,,0.0487,,ok,no_history +polars,freeze_panes,0.439542,0.520458,,,,,,,,,0.1841,,ok,no_history +tablib,freeze_panes,1.360458,1.414291,,,,1.808959,2.014916,,,,0.0396,0.1139,ok,no_history +openpyxl,named_ranges,1.08575,1.125334,,,,1.367875,1.476167,,,,0.0365,0.0792,ok,no_history +xlsxwriter,named_ranges,,,,,,1.652041,2.198167,,,,,0.3306,high,no_history +python-calamine,named_ranges,0.045292,0.048542,,,,,,,,,0.0718,,ok,no_history +wolfxl,named_ranges,0.470875,0.524333,,,,1.127291,1.191042,,,,0.1135,0.0566,ok,no_history +pylightxl,named_ranges,,,,,,0.225625,0.233334,,,,,0.0342,ok,no_history +xlrd,named_ranges,,,,,,,,,,,,,ok,no_history +pyexcel,named_ranges,1.19925,1.433416,,,,1.389667,1.506458,,,,0.1953,0.084,ok,no_history +xlwt,named_ranges,,,,,,0.148959,0.158916,,,,,0.0668,ok,no_history +pandas,named_ranges,1.450958,1.510334,,,,1.457959,1.511833,,,,0.0409,0.037,ok,no_history +xlsxwriter-constmem,named_ranges,,,,,,1.573417,1.809875,,,,,0.1503,ok,no_history +openpyxl-readonly,named_ranges,0.848459,0.871333,,,,,,,,,0.027,,ok,no_history +polars,named_ranges,0.407625,0.4955,,,,,,,,,0.2156,,high,no_history +tablib,named_ranges,1.150333,1.167042,,,,1.332375,1.438333,,,,0.0145,0.0795,ok,no_history +openpyxl,tables,1.395542,1.436375,,,,1.082416,1.131625,,,,0.0293,0.0455,ok,no_history +xlsxwriter,tables,,,,,,1.331208,1.704417,,,,,0.2804,high,no_history +python-calamine,tables,0.049042,0.054542,,,,,,,,,0.1121,,ok,no_history +wolfxl,tables,0.505292,0.528041,,,,1.037584,1.066416,,,,0.045,0.0278,ok,no_history +pylightxl,tables,,,,,,0.203292,0.223958,,,,,0.1017,ok,no_history +xlrd,tables,,,,,,,,,,,,,ok,no_history +pyexcel,tables,1.720291,2.0175,,,,1.110916,1.731792,,,,0.1728,0.5589,high,no_history +xlwt,tables,,,,,,0.129458,0.133459,,,,,0.0309,ok,no_history +pandas,tables,1.607792,1.677041,,,,1.196375,1.2465,,,,0.0431,0.0419,ok,no_history +xlsxwriter-constmem,tables,,,,,,1.378416,1.792416,,,,,0.3003,high,no_history +openpyxl-readonly,tables,0.902875,1.046458,,,,,,,,,0.159,,ok,no_history +polars,tables,0.370833,0.475916,,,,,,,,,0.2834,,high,no_history +tablib,tables,1.331125,1.459167,,,,1.082375,1.119875,,,,0.0962,0.0346,ok,no_history \ No newline at end of file diff --git a/results-2026-10-02/perf/pins.txt b/results-2026-10-02/perf/pins.txt new file mode 100644 index 0000000..9340ef7 --- /dev/null +++ b/results-2026-10-02/perf/pins.txt @@ -0,0 +1,13 @@ +wolfxl==2.0.5 +openpyxl==3.1.5 +xlsxwriter==3.2.9 +python-calamine==0.8.2 +pylightxl==1.61 +xlrd==2.0.2 +pyexcel==0.7.6 +pyexcel-xlsx==0.6.1 +xlwt==1.3.0 +pandas==3.0.6 +polars==1.44.2 +fastexcel==0.21.0 +tablib==3.10.0 diff --git a/results-2026-10-02/perf/pip-freeze.txt b/results-2026-10-02/perf/pip-freeze.txt new file mode 100644 index 0000000..2a7f436 --- /dev/null +++ b/results-2026-10-02/perf/pip-freeze.txt @@ -0,0 +1,49 @@ +annotated-doc==0.0.5 +annotated-types==0.8.0 +appscript==1.4.0 +contourpy==1.4.0 +cycler==0.12.1 +defusedxml==0.7.1 +et-xmlfile==2.0.0 +excelbench @ file://~/wolf-lane/officelibs-perf/src +fastexcel==0.21.0 +fonttools==4.66.1 +kiwisolver==1.5.1 +lml==0.2.0 +lxml==6.1.3 +markdown-it-py==4.2.0 +matplotlib==3.11.2 +mdurl==0.1.2 +narwhals==2.26.0 +numpy==2.5.3 +openpyxl==3.1.5 +packaging==26.3 +pandas==3.0.6 +pillow==12.3.0 +plotly==7.1.0 +polars==1.44.2 +polars-runtime-32==1.44.2 +psutil==7.2.2 +pydantic==2.13.5 +pydantic-core==2.46.5 +pyexcel==0.7.6 +pyexcel-io==0.6.8 +pyexcel-xlsx==0.6.1 +pygments==2.21.0 +pylightxl==1.61 +pyparsing==3.3.3 +python-calamine==0.8.2 +python-dateutil==2.9.0.post0 +rich==15.0.0 +shellingham==1.5.4 +six==1.17.0 +tablib==3.10.0 +texttable==1.7.0 +typer==0.27.2 +typing-extensions==4.16.0 +typing-inspection==0.4.4 +wolfxl==2.0.5 +xlrd==2.0.2 +xlsxwriter==3.2.9 +xlwings==0.37.5 +xlwt==1.3.0 diff --git a/results-2026-10-02/perf/results.json b/results-2026-10-02/perf/results.json new file mode 100644 index 0000000..7bfe583 --- /dev/null +++ b/results-2026-10-02/perf/results.json @@ -0,0 +1,9207 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-10-02T08:33:41.795781+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx", + "python": "3.12.3", + "commit": null, + "config": { + "warmup": 3, + "iters": 25, + "iteration_policy": "fixed", + "breakdown": false + }, + "run_environment": { + "cpu_model": "arm", + "core_count": 14, + "memory_total_mb": 24576.0 + } + }, + "libraries": { + "openpyxl": { + "name": "openpyxl", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "xlsxwriter": { + "name": "xlsxwriter", + "version": "3.2.9", + "language": "python", + "capabilities": [ + "write" + ] + }, + "python-calamine": { + "name": "python-calamine", + "version": "0.8.2", + "language": "python", + "capabilities": [ + "read" + ] + }, + "wolfxl": { + "name": "wolfxl", + "version": "2.0.5", + "language": "python", + "capabilities": [ + "modify", + "read", + "write" + ] + }, + "pylightxl": { + "name": "pylightxl", + "version": "1.61", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "xlrd": { + "name": "xlrd", + "version": "2.0.2", + "language": "python", + "capabilities": [ + "read" + ] + }, + "pyexcel": { + "name": "pyexcel", + "version": "0.7.6", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "xlwt": { + "name": "xlwt", + "version": "1.3.0", + "language": "python", + "capabilities": [ + "write" + ] + }, + "pandas": { + "name": "pandas", + "version": "3.0.6", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "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.44.2", + "language": "python", + "capabilities": [ + "read" + ] + }, + "tablib": { + "name": "tablib", + "version": "3.10.0", + "language": "python", + "capabilities": [ + "read", + "write" + ] + } + }, + "results": [ + { + "feature": "cell_values", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.184708, + "p50": 1.257625, + "p95": 1.545292 + }, + "cpu_ms": { + "min": 1.185, + "p50": 1.258, + "p95": 1.545 + }, + "rss_peak_mb": 155.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.257625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.18, + "p50": 1.21875, + "p95": 1.288042 + }, + "cpu_ms": { + "min": 1.18, + "p50": 1.219, + "p95": 1.288 + }, + "rss_peak_mb": 156.03125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.21875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.525167, + "p50": 1.594916, + "p95": 2.034042 + }, + "cpu_ms": { + "min": 1.525, + "p50": 1.595, + "p95": 2.034 + }, + "rss_peak_mb": 156.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.594916, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "cell_values", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.611959, + "p50": 0.616458, + "p95": 0.626333 + }, + "cpu_ms": { + "min": 0.612, + "p50": 0.616, + "p95": 0.627 + }, + "rss_peak_mb": 156.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.616458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "cell_values", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.6515, + "p50": 0.661167, + "p95": 0.73025 + }, + "cpu_ms": { + "min": 0.652, + "p50": 0.661, + "p95": 0.73 + }, + "rss_peak_mb": 158.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.661167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.165167, + "p50": 1.184333, + "p95": 1.27775 + }, + "cpu_ms": { + "min": 1.165, + "p50": 1.184, + "p95": 1.278 + }, + "rss_peak_mb": 158.796875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.184333, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.237042, + "p50": 1.26225, + "p95": 1.280667 + }, + "cpu_ms": { + "min": 1.237, + "p50": 1.263, + "p95": 1.281 + }, + "rss_peak_mb": 159.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.26225, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + { + "feature": "cell_values", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "cell_values", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.379167, + "p50": 1.404875, + "p95": 1.437583 + }, + "cpu_ms": { + "min": 1.379, + "p50": 1.404, + "p95": 1.437 + }, + "rss_peak_mb": 159.65625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.404875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + { + "feature": "cell_values", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.219958, + "p50": 0.22425, + "p95": 0.276959 + }, + "cpu_ms": { + "min": 0.22, + "p50": 0.224, + "p95": 0.276 + }, + "rss_peak_mb": 159.6875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.22425, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "cell_values", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.679083, + "p50": 1.707042, + "p95": 1.824125 + }, + "cpu_ms": { + "min": 1.679, + "p50": 1.707, + "p95": 1.825 + }, + "rss_peak_mb": 160.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.707042, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.37475, + "p50": 1.47725, + "p95": 1.548875 + }, + "cpu_ms": { + "min": 1.374, + "p50": 1.477, + "p95": 1.549 + }, + "rss_peak_mb": 160.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.47725, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "cell_values", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.5315, + "p50": 1.587125, + "p95": 1.99525 + }, + "cpu_ms": { + "min": 1.531, + "p50": 1.587, + "p95": 1.996 + }, + "rss_peak_mb": 160.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.587125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "cell_values", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 5.554792, + "p50": 5.687583, + "p95": 5.941375 + }, + "cpu_ms": { + "min": 5.555, + "p50": 5.688, + "p95": 5.941 + }, + "rss_peak_mb": 161.6875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 5.687583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "cell_values", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.25725, + "p50": 0.316292, + "p95": 0.423584 + }, + "cpu_ms": { + "min": 0.34, + "p50": 0.587, + "p95": 1.04 + }, + "rss_peak_mb": 175.796875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.316292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "cell_values", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.360458, + "p50": 1.372458, + "p95": 1.399041 + }, + "cpu_ms": { + "min": 1.36, + "p50": 1.372, + "p95": 1.398 + }, + "rss_peak_mb": 176.21875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.372458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.261459, + "p50": 1.304959, + "p95": 1.375375 + }, + "cpu_ms": { + "min": 1.262, + "p50": 1.305, + "p95": 1.375 + }, + "rss_peak_mb": 176.34375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.304959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.059083, + "p50": 1.105625, + "p95": 1.1325 + }, + "cpu_ms": { + "min": 1.059, + "p50": 1.106, + "p95": 1.133 + }, + "rss_peak_mb": 176.546875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.105625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.308334, + "p50": 1.345334, + "p95": 1.407083 + }, + "cpu_ms": { + "min": 1.308, + "p50": 1.346, + "p95": 1.408 + }, + "rss_peak_mb": 176.5625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.345334, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.461917, + "p50": 1.529417, + "p95": 1.992916 + }, + "cpu_ms": { + "min": 1.462, + "p50": 1.53, + "p95": 1.993 + }, + "rss_peak_mb": 176.625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.529417, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "formulas", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.121459, + "p50": 0.122375, + "p95": 0.124458 + }, + "cpu_ms": { + "min": 0.121, + "p50": 0.122, + "p95": 0.125 + }, + "rss_peak_mb": 176.625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.122375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "formulas", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.562833, + "p50": 0.571292, + "p95": 0.631542 + }, + "cpu_ms": { + "min": 0.563, + "p50": 0.572, + "p95": 0.632 + }, + "rss_peak_mb": 176.640625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.571292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.149042, + "p50": 1.1715, + "p95": 1.327666 + }, + "cpu_ms": { + "min": 1.149, + "p50": 1.172, + "p95": 1.328 + }, + "rss_peak_mb": 176.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.1715, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.02125, + "p50": 1.115709, + "p95": 1.141458 + }, + "cpu_ms": { + "min": 1.021, + "p50": 1.116, + "p95": 1.141 + }, + "rss_peak_mb": 176.78125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.115709, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 0.240958, + "p50": 0.257708, + "p95": 0.287459 + }, + "cpu_ms": { + "min": 0.241, + "p50": 0.258, + "p95": 0.288 + }, + "rss_peak_mb": 176.796875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.257708, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "formulas", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.138167, + "p50": 1.194125, + "p95": 1.237792 + }, + "cpu_ms": { + "min": 1.139, + "p50": 1.193, + "p95": 1.238 + }, + "rss_peak_mb": 176.96875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.194125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.332208, + "p50": 1.386458, + "p95": 1.465583 + }, + "cpu_ms": { + "min": 1.331, + "p50": 1.386, + "p95": 1.466 + }, + "rss_peak_mb": 177.03125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.386458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.251417, + "p50": 0.256042, + "p95": 0.338625 + }, + "cpu_ms": { + "min": 0.251, + "p50": 0.256, + "p95": 0.336 + }, + "rss_peak_mb": 177.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.256042, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "formulas", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.432334, + "p50": 1.519666, + "p95": 1.54975 + }, + "cpu_ms": { + "min": 1.432, + "p50": 1.52, + "p95": 1.549 + }, + "rss_peak_mb": 177.203125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.519666, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.548625, + "p50": 1.596541, + "p95": 1.85925 + }, + "cpu_ms": { + "min": 1.549, + "p50": 1.596, + "p95": 1.859 + }, + "rss_peak_mb": 177.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.596541, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "formulas", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.624917, + "p50": 1.707, + "p95": 2.169792 + }, + "cpu_ms": { + "min": 1.626, + "p50": 1.708, + "p95": 2.17 + }, + "rss_peak_mb": 177.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.707, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "formulas", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.409083, + "p50": 1.434709, + "p95": 1.670375 + }, + "cpu_ms": { + "min": 1.409, + "p50": 1.435, + "p95": 1.669 + }, + "rss_peak_mb": 177.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.434709, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "formulas", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.324625, + "p50": 0.406083, + "p95": 0.537333 + }, + "cpu_ms": { + "min": 0.533, + "p50": 0.857, + "p95": 1.379 + }, + "rss_peak_mb": 178.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.406083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "formulas", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.094042, + "p50": 1.158542, + "p95": 1.186375 + }, + "cpu_ms": { + "min": 1.094, + "p50": 1.159, + "p95": 1.186 + }, + "rss_peak_mb": 178.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.158542, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.332833, + "p50": 1.367083, + "p95": 1.432666 + }, + "cpu_ms": { + "min": 1.333, + "p50": 1.368, + "p95": 1.433 + }, + "rss_peak_mb": 178.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.367083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.642917, + "p50": 1.672375, + "p95": 1.703791 + }, + "cpu_ms": { + "min": 1.643, + "p50": 1.673, + "p95": 1.705 + }, + "rss_peak_mb": 178.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.672375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.614042, + "p50": 1.789042, + "p95": 1.852458 + }, + "cpu_ms": { + "min": 1.613, + "p50": 1.782, + "p95": 1.853 + }, + "rss_peak_mb": 178.765625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.789042, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.742708, + "p50": 1.820959, + "p95": 2.232625 + }, + "cpu_ms": { + "min": 1.743, + "p50": 1.821, + "p95": 2.233 + }, + "rss_peak_mb": 178.96875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.820959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "text_formatting", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.071209, + "p50": 0.071958, + "p95": 0.079625 + }, + "cpu_ms": { + "min": 0.07, + "p50": 0.072, + "p95": 0.079 + }, + "rss_peak_mb": 178.96875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.071958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "text_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.809833, + "p50": 0.835667, + "p95": 0.903125 + }, + "cpu_ms": { + "min": 0.809, + "p50": 0.836, + "p95": 0.904 + }, + "rss_peak_mb": 178.984375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.835667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.192042, + "p50": 1.218959, + "p95": 1.296792 + }, + "cpu_ms": { + "min": 1.192, + "p50": 1.219, + "p95": 1.296 + }, + "rss_peak_mb": 179.28125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.218959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.394167, + "p50": 1.420541, + "p95": 1.46475 + }, + "cpu_ms": { + "min": 1.395, + "p50": 1.42, + "p95": 1.465 + }, + "rss_peak_mb": 179.28125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.420541, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + { + "feature": "text_formatting", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "text_formatting", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.672833, + "p50": 1.732375, + "p95": 1.790833 + }, + "cpu_ms": { + "min": 1.673, + "p50": 1.733, + "p95": 1.782 + }, + "rss_peak_mb": 179.65625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.732375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + { + "feature": "text_formatting", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.303167, + "p50": 0.335542, + "p95": 0.627875 + }, + "cpu_ms": { + "min": 0.303, + "p50": 0.335, + "p95": 0.411 + }, + "rss_peak_mb": 179.65625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.335542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "text_formatting", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.893875, + "p50": 1.939375, + "p95": 1.963875 + }, + "cpu_ms": { + "min": 1.893, + "p50": 1.939, + "p95": 1.964 + }, + "rss_peak_mb": 179.78125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.939375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.377042, + "p50": 1.438709, + "p95": 1.538917 + }, + "cpu_ms": { + "min": 1.377, + "p50": 1.438, + "p95": 1.538 + }, + "rss_peak_mb": 179.8125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.438709, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "text_formatting", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.746042, + "p50": 1.919833, + "p95": 2.216458 + }, + "cpu_ms": { + "min": 1.746, + "p50": 1.92, + "p95": 2.216 + }, + "rss_peak_mb": 179.9375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.919833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "text_formatting", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.349084, + "p50": 1.417125, + "p95": 1.458 + }, + "cpu_ms": { + "min": 1.349, + "p50": 1.416, + "p95": 1.457 + }, + "rss_peak_mb": 179.9375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.417125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "text_formatting", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.222875, + "p50": 0.250208, + "p95": 0.297291 + }, + "cpu_ms": { + "min": 0.326, + "p50": 0.453, + "p95": 0.641 + }, + "rss_peak_mb": 179.953125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.250208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "text_formatting", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.70225, + "p50": 1.733708, + "p95": 1.850916 + }, + "cpu_ms": { + "min": 1.703, + "p50": 1.734, + "p95": 1.851 + }, + "rss_peak_mb": 180.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.733708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.219709, + "p50": 1.254459, + "p95": 1.318875 + }, + "cpu_ms": { + "min": 1.219, + "p50": 1.254, + "p95": 1.318 + }, + "rss_peak_mb": 180.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.254459, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.936875, + "p50": 0.982292, + "p95": 1.034458 + }, + "cpu_ms": { + "min": 0.937, + "p50": 0.983, + "p95": 1.034 + }, + "rss_peak_mb": 180.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.982292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.164166, + "p50": 1.197167, + "p95": 1.245416 + }, + "cpu_ms": { + "min": 1.164, + "p50": 1.197, + "p95": 1.245 + }, + "rss_peak_mb": 180.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.197167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.467667, + "p50": 1.568208, + "p95": 1.973125 + }, + "cpu_ms": { + "min": 1.468, + "p50": 1.569, + "p95": 1.972 + }, + "rss_peak_mb": 180.203125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.568208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "background_colors", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.052709, + "p50": 0.05325, + "p95": 0.056625 + }, + "cpu_ms": { + "min": 0.052, + "p50": 0.054, + "p95": 0.057 + }, + "rss_peak_mb": 180.203125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.05325, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "background_colors", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.557542, + "p50": 0.579792, + "p95": 0.646458 + }, + "cpu_ms": { + "min": 0.558, + "p50": 0.58, + "p95": 0.646 + }, + "rss_peak_mb": 180.21875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.579792, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.062334, + "p50": 1.123583, + "p95": 1.22925 + }, + "cpu_ms": { + "min": 1.063, + "p50": 1.123, + "p95": 1.229 + }, + "rss_peak_mb": 180.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.123583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.820542, + "p50": 0.898208, + "p95": 0.914083 + }, + "cpu_ms": { + "min": 0.821, + "p50": 0.898, + "p95": 0.913 + }, + "rss_peak_mb": 180.296875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.898208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + { + "feature": "background_colors", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "background_colors", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.982917, + "p50": 1.041708, + "p95": 1.083167 + }, + "cpu_ms": { + "min": 0.982, + "p50": 1.042, + "p95": 1.083 + }, + "rss_peak_mb": 180.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.041708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + { + "feature": "background_colors", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.177458, + "p50": 0.181625, + "p95": 0.189792 + }, + "cpu_ms": { + "min": 0.178, + "p50": 0.182, + "p95": 0.191 + }, + "rss_peak_mb": 180.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.181625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "background_colors", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.118875, + "p50": 1.197, + "p95": 1.3 + }, + "cpu_ms": { + "min": 1.118, + "p50": 1.197, + "p95": 1.291 + }, + "rss_peak_mb": 180.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.197, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.251292, + "p50": 1.302292, + "p95": 1.363542 + }, + "cpu_ms": { + "min": 1.251, + "p50": 1.302, + "p95": 1.364 + }, + "rss_peak_mb": 180.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.302292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "background_colors", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.477417, + "p50": 1.548416, + "p95": 1.969291 + }, + "cpu_ms": { + "min": 1.478, + "p50": 1.548, + "p95": 1.97 + }, + "rss_peak_mb": 180.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.548416, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "background_colors", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.774958, + "p50": 0.83675, + "p95": 0.871833 + }, + "cpu_ms": { + "min": 0.775, + "p50": 0.837, + "p95": 0.872 + }, + "rss_peak_mb": 180.5, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.83675, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "background_colors", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.19275, + "p50": 0.236125, + "p95": 0.317709 + }, + "cpu_ms": { + "min": 0.304, + "p50": 0.453, + "p95": 0.824 + }, + "rss_peak_mb": 180.578125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.236125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "background_colors", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.930458, + "p50": 0.993458, + "p95": 1.017834 + }, + "cpu_ms": { + "min": 0.93, + "p50": 0.994, + "p95": 1.017 + }, + "rss_peak_mb": 180.671875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.993458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.063292, + "p50": 1.106792, + "p95": 1.185833 + }, + "cpu_ms": { + "min": 1.063, + "p50": 1.106, + "p95": 1.186 + }, + "rss_peak_mb": 180.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.106792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.949375, + "p50": 1.008583, + "p95": 1.060083 + }, + "cpu_ms": { + "min": 0.949, + "p50": 1.006, + "p95": 1.059 + }, + "rss_peak_mb": 180.765625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.008583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.13075, + "p50": 1.1675, + "p95": 1.202458 + }, + "cpu_ms": { + "min": 1.13, + "p50": 1.168, + "p95": 1.202 + }, + "rss_peak_mb": 180.765625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.1675, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.373, + "p50": 1.390916, + "p95": 1.884959 + }, + "cpu_ms": { + "min": 1.373, + "p50": 1.391, + "p95": 1.884 + }, + "rss_peak_mb": 180.765625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.390916, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "number_formats", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.054084, + "p50": 0.055083, + "p95": 0.057417 + }, + "cpu_ms": { + "min": 0.053, + "p50": 0.055, + "p95": 0.058 + }, + "rss_peak_mb": 180.765625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.055083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "number_formats", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.569584, + "p50": 0.590708, + "p95": 0.63375 + }, + "cpu_ms": { + "min": 0.569, + "p50": 0.591, + "p95": 0.634 + }, + "rss_peak_mb": 180.78125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.590708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.054709, + "p50": 1.083958, + "p95": 1.337167 + }, + "cpu_ms": { + "min": 1.055, + "p50": 1.083, + "p95": 1.337 + }, + "rss_peak_mb": 180.78125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.083958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.849875, + "p50": 0.93225, + "p95": 0.949792 + }, + "cpu_ms": { + "min": 0.85, + "p50": 0.933, + "p95": 0.95 + }, + "rss_peak_mb": 180.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.93225, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + { + "feature": "number_formats", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "number_formats", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.983709, + "p50": 1.06275, + "p95": 1.116333 + }, + "cpu_ms": { + "min": 0.983, + "p50": 1.062, + "p95": 1.116 + }, + "rss_peak_mb": 181.0625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.06275, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + { + "feature": "number_formats", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.180375, + "p50": 0.186584, + "p95": 0.238 + }, + "cpu_ms": { + "min": 0.18, + "p50": 0.187, + "p95": 0.238 + }, + "rss_peak_mb": 181.0625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.186584, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "number_formats", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.125875, + "p50": 1.230667, + "p95": 1.279375 + }, + "cpu_ms": { + "min": 1.127, + "p50": 1.231, + "p95": 1.278 + }, + "rss_peak_mb": 181.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.230667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.258416, + "p50": 1.316875, + "p95": 1.713 + }, + "cpu_ms": { + "min": 1.258, + "p50": 1.317, + "p95": 1.712 + }, + "rss_peak_mb": 181.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.316875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "number_formats", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.505417, + "p50": 1.737083, + "p95": 1.966667 + }, + "cpu_ms": { + "min": 1.505, + "p50": 1.729, + "p95": 1.94 + }, + "rss_peak_mb": 181.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.737083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "number_formats", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.797333, + "p50": 0.857083, + "p95": 0.8815 + }, + "cpu_ms": { + "min": 0.798, + "p50": 0.858, + "p95": 0.882 + }, + "rss_peak_mb": 181.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.857083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "number_formats", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.194375, + "p50": 0.235083, + "p95": 0.2885 + }, + "cpu_ms": { + "min": 0.286, + "p50": 0.419, + "p95": 0.716 + }, + "rss_peak_mb": 181.09375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.235083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "number_formats", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.947167, + "p50": 1.006291, + "p95": 1.113416 + }, + "cpu_ms": { + "min": 0.947, + "p50": 1.006, + "p95": 1.114 + }, + "rss_peak_mb": 181.15625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.006291, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.077333, + "p50": 1.120667, + "p95": 1.17 + }, + "cpu_ms": { + "min": 1.077, + "p50": 1.12, + "p95": 1.17 + }, + "rss_peak_mb": 181.21875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.120667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.121, + "p50": 1.176833, + "p95": 1.221875 + }, + "cpu_ms": { + "min": 1.12, + "p50": 1.177, + "p95": 1.223 + }, + "rss_peak_mb": 181.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.176833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.273333, + "p50": 1.3235, + "p95": 1.396 + }, + "cpu_ms": { + "min": 1.274, + "p50": 1.322, + "p95": 1.396 + }, + "rss_peak_mb": 181.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.3235, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.543375, + "p50": 1.579542, + "p95": 1.854916 + }, + "cpu_ms": { + "min": 1.543, + "p50": 1.58, + "p95": 1.855 + }, + "rss_peak_mb": 181.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.579542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "alignment", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.047708, + "p50": 0.048292, + "p95": 0.050208 + }, + "cpu_ms": { + "min": 0.047, + "p50": 0.048, + "p95": 0.05 + }, + "rss_peak_mb": 181.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.048292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "alignment", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.627709, + "p50": 0.650375, + "p95": 0.694792 + }, + "cpu_ms": { + "min": 0.628, + "p50": 0.65, + "p95": 0.695 + }, + "rss_peak_mb": 181.421875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.650375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.0805, + "p50": 1.098958, + "p95": 1.182375 + }, + "cpu_ms": { + "min": 1.079, + "p50": 1.099, + "p95": 1.182 + }, + "rss_peak_mb": 181.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.098958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature" + }, + { + "feature": "alignment", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "alignment", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.165375, + "p50": 1.225875, + "p95": 1.26825 + }, + "cpu_ms": { + "min": 1.166, + "p50": 1.226, + "p95": 1.268 + }, + "rss_peak_mb": 181.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.225875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells" + }, + { + "feature": "alignment", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.210334, + "p50": 0.215167, + "p95": 0.232958 + }, + "cpu_ms": { + "min": 0.211, + "p50": 0.215, + "p95": 0.233 + }, + "rss_peak_mb": 181.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.215167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "alignment", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.345875, + "p50": 1.416875, + "p95": 1.542375 + }, + "cpu_ms": { + "min": 1.345, + "p50": 1.416, + "p95": 1.534 + }, + "rss_peak_mb": 181.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.416875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.306875, + "p50": 1.352916, + "p95": 1.407209 + }, + "cpu_ms": { + "min": 1.307, + "p50": 1.353, + "p95": 1.407 + }, + "rss_peak_mb": 181.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.352916, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "alignment", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.546417, + "p50": 1.626834, + "p95": 1.990375 + }, + "cpu_ms": { + "min": 1.546, + "p50": 1.627, + "p95": 1.986 + }, + "rss_peak_mb": 181.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.626834, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "alignment", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.868708, + "p50": 0.924792, + "p95": 0.955334 + }, + "cpu_ms": { + "min": 0.868, + "p50": 0.924, + "p95": 0.956 + }, + "rss_peak_mb": 181.71875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.924792, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "alignment", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.187625, + "p50": 0.224375, + "p95": 0.274916 + }, + "cpu_ms": { + "min": 0.264, + "p50": 0.446, + "p95": 0.576 + }, + "rss_peak_mb": 181.734375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.224375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "alignment", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.137166, + "p50": 1.208, + "p95": 1.379708 + }, + "cpu_ms": { + "min": 1.138, + "p50": 1.207, + "p95": 1.379 + }, + "rss_peak_mb": 181.796875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.121416, + "p50": 1.159, + "p95": 1.222583 + }, + "cpu_ms": { + "min": 1.121, + "p50": 1.159, + "p95": 1.223 + }, + "rss_peak_mb": 181.796875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.159, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.636375, + "p50": 1.679375, + "p95": 1.80325 + }, + "cpu_ms": { + "min": 1.636, + "p50": 1.679, + "p95": 1.803 + }, + "rss_peak_mb": 181.8125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.679375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 2.000167, + "p50": 2.063291, + "p95": 2.319584 + }, + "cpu_ms": { + "min": 2.001, + "p50": 2.06, + "p95": 2.129 + }, + "rss_peak_mb": 181.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.063291, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.900084, + "p50": 2.010917, + "p95": 2.458209 + }, + "cpu_ms": { + "min": 1.9, + "p50": 2.011, + "p95": 2.458 + }, + "rss_peak_mb": 181.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.010917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "borders", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.059458, + "p50": 0.060375, + "p95": 0.065333 + }, + "cpu_ms": { + "min": 0.059, + "p50": 0.06, + "p95": 0.066 + }, + "rss_peak_mb": 181.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.060375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "borders", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.923875, + "p50": 0.977166, + "p95": 1.006125 + }, + "cpu_ms": { + "min": 0.925, + "p50": 0.977, + "p95": 1.007 + }, + "rss_peak_mb": 181.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.977166, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.34225, + "p50": 1.402292, + "p95": 1.497625 + }, + "cpu_ms": { + "min": 1.342, + "p50": 1.401, + "p95": 1.498 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.402292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature" + }, + { + "feature": "borders", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "borders", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.725, + "p50": 1.759708, + "p95": 1.803584 + }, + "cpu_ms": { + "min": 1.726, + "p50": 1.759, + "p95": 1.804 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.759708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells" + }, + { + "feature": "borders", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.377333, + "p50": 0.394541, + "p95": 0.45075 + }, + "cpu_ms": { + "min": 0.378, + "p50": 0.395, + "p95": 0.451 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.394541, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "borders", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.929125, + "p50": 2.001834, + "p95": 2.273791 + }, + "cpu_ms": { + "min": 1.93, + "p50": 2.001, + "p95": 2.273 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 2.001834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.417667, + "p50": 1.484917, + "p95": 1.537333 + }, + "cpu_ms": { + "min": 1.418, + "p50": 1.485, + "p95": 1.537 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.484917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "borders", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.898416, + "p50": 1.953875, + "p95": 2.318375 + }, + "cpu_ms": { + "min": 1.899, + "p50": 1.954, + "p95": 2.319 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.953875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "borders", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.231, + "p50": 1.273042, + "p95": 1.314416 + }, + "cpu_ms": { + "min": 1.231, + "p50": 1.274, + "p95": 1.314 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.273042, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "borders", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.213792, + "p50": 0.2645, + "p95": 0.317208 + }, + "cpu_ms": { + "min": 0.322, + "p50": 0.493, + "p95": 0.814 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.2645, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "borders", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.713375, + "p50": 1.759125, + "p95": 2.100958 + }, + "cpu_ms": { + "min": 1.713, + "p50": 1.759, + "p95": 2.101 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.759125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.255, + "p50": 1.323958, + "p95": 1.47875 + }, + "cpu_ms": { + "min": 1.255, + "p50": 1.324, + "p95": 1.479 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.323958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.86825, + "p50": 0.9385, + "p95": 1.040417 + }, + "cpu_ms": { + "min": 0.868, + "p50": 0.938, + "p95": 1.041 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.9385, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.081833, + "p50": 1.241542, + "p95": 1.296541 + }, + "cpu_ms": { + "min": 1.081, + "p50": 1.242, + "p95": 1.297 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.241542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.305375, + "p50": 1.349833, + "p95": 1.851041 + }, + "cpu_ms": { + "min": 1.305, + "p50": 1.349, + "p95": 1.838 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.349833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "dimensions", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.052458, + "p50": 0.053, + "p95": 0.054583 + }, + "cpu_ms": { + "min": 0.052, + "p50": 0.053, + "p95": 0.054 + }, + "rss_peak_mb": 182.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.053, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "dimensions", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.507125, + "p50": 0.524125, + "p95": 0.559042 + }, + "cpu_ms": { + "min": 0.507, + "p50": 0.524, + "p95": 0.559 + }, + "rss_peak_mb": 182.125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.524125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.016375, + "p50": 1.038792, + "p95": 1.1755 + }, + "cpu_ms": { + "min": 1.016, + "p50": 1.039, + "p95": 1.163 + }, + "rss_peak_mb": 182.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.038792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.789708, + "p50": 0.86775, + "p95": 0.893083 + }, + "cpu_ms": { + "min": 0.79, + "p50": 0.867, + "p95": 0.893 + }, + "rss_peak_mb": 182.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.86775, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature" + }, + { + "feature": "dimensions", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "dimensions", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.954916, + "p50": 1.014125, + "p95": 1.054666 + }, + "cpu_ms": { + "min": 0.955, + "p50": 1.014, + "p95": 1.054 + }, + "rss_peak_mb": 182.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.014125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support set_row_height: pyexcel does not expose row dimension writing" + }, + { + "feature": "dimensions", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.148792, + "p50": 0.161708, + "p95": 0.222 + }, + "cpu_ms": { + "min": 0.148, + "p50": 0.161, + "p95": 0.222 + }, + "rss_peak_mb": 182.140625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.161708, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "dimensions", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.164167, + "p50": 1.462792, + "p95": 1.632917 + }, + "cpu_ms": { + "min": 1.164, + "p50": 1.463, + "p95": 1.633 + }, + "rss_peak_mb": 182.75, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.462792, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.2185, + "p50": 1.289208, + "p95": 1.429709 + }, + "cpu_ms": { + "min": 1.218, + "p50": 1.289, + "p95": 1.429 + }, + "rss_peak_mb": 182.75, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.289208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "dimensions", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.5445, + "p50": 1.640792, + "p95": 2.237917 + }, + "cpu_ms": { + "min": 1.545, + "p50": 1.619, + "p95": 2.238 + }, + "rss_peak_mb": 182.75, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.640792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "dimensions", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.754417, + "p50": 0.836541, + "p95": 0.927667 + }, + "cpu_ms": { + "min": 0.755, + "p50": 0.837, + "p95": 0.928 + }, + "rss_peak_mb": 182.75, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.836541, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "dimensions", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.268291, + "p50": 0.357375, + "p95": 0.454542 + }, + "cpu_ms": { + "min": 0.721, + "p50": 1.158, + "p95": 1.603 + }, + "rss_peak_mb": 183.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.357375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "dimensions", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.9005, + "p50": 1.031292, + "p95": 1.181167 + }, + "cpu_ms": { + "min": 0.9, + "p50": 1.031, + "p95": 1.181 + }, + "rss_peak_mb": 183.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.031292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.098958, + "p50": 1.239583, + "p95": 1.373958 + }, + "cpu_ms": { + "min": 1.099, + "p50": 1.24, + "p95": 1.343 + }, + "rss_peak_mb": 183.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.239583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.22675, + "p50": 1.311708, + "p95": 1.4105 + }, + "cpu_ms": { + "min": 1.226, + "p50": 1.311, + "p95": 1.411 + }, + "rss_peak_mb": 183.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.311708, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.689167, + "p50": 1.736125, + "p95": 1.925375 + }, + "cpu_ms": { + "min": 1.689, + "p50": 1.736, + "p95": 1.92 + }, + "rss_peak_mb": 183.109375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.736125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.886208, + "p50": 1.951084, + "p95": 2.414709 + }, + "cpu_ms": { + "min": 1.887, + "p50": 1.944, + "p95": 2.414 + }, + "rss_peak_mb": 183.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.951084, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "multiple_sheets", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.056042, + "p50": 0.056834, + "p95": 0.062 + }, + "cpu_ms": { + "min": 0.056, + "p50": 0.057, + "p95": 0.061 + }, + "rss_peak_mb": 183.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.056834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "multiple_sheets", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.511708, + "p50": 0.536333, + "p95": 0.580625 + }, + "cpu_ms": { + "min": 0.511, + "p50": 0.536, + "p95": 0.58 + }, + "rss_peak_mb": 183.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.536333, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.252375, + "p50": 1.300917, + "p95": 1.496042 + }, + "cpu_ms": { + "min": 1.252, + "p50": 1.301, + "p95": 1.495 + }, + "rss_peak_mb": 183.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.300917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.230167, + "p50": 1.287458, + "p95": 1.4425 + }, + "cpu_ms": { + "min": 1.231, + "p50": 1.287, + "p95": 1.443 + }, + "rss_peak_mb": 183.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.287458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 0.308791, + "p50": 0.32325, + "p95": 0.379625 + }, + "cpu_ms": { + "min": 0.309, + "p50": 0.323, + "p95": 0.38 + }, + "rss_peak_mb": 183.25, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.32325, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "multiple_sheets", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.384125, + "p50": 1.649875, + "p95": 2.731792 + }, + "cpu_ms": { + "min": 1.384, + "p50": 1.64, + "p95": 2.149 + }, + "rss_peak_mb": 183.40625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.649875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.6645, + "p50": 2.307, + "p95": 2.692583 + }, + "cpu_ms": { + "min": 1.664, + "p50": 2.201, + "p95": 2.637 + }, + "rss_peak_mb": 183.40625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.307, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.169167, + "p50": 0.176209, + "p95": 0.18475 + }, + "cpu_ms": { + "min": 0.168, + "p50": 0.176, + "p95": 0.184 + }, + "rss_peak_mb": 183.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.176209, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "multiple_sheets", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.726167, + "p50": 1.763834, + "p95": 1.835708 + }, + "cpu_ms": { + "min": 1.726, + "p50": 1.764, + "p95": 1.835 + }, + "rss_peak_mb": 183.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.763834, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.966, + "p50": 2.018, + "p95": 2.372875 + }, + "cpu_ms": { + "min": 1.965, + "p50": 2.017, + "p95": 2.372 + }, + "rss_peak_mb": 183.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.018, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "multiple_sheets", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.886209, + "p50": 2.003416, + "p95": 2.45025 + }, + "cpu_ms": { + "min": 1.887, + "p50": 2.004, + "p95": 2.451 + }, + "rss_peak_mb": 183.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.003416, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "multiple_sheets", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.899708, + "p50": 0.972958, + "p95": 1.006542 + }, + "cpu_ms": { + "min": 0.899, + "p50": 0.973, + "p95": 1.006 + }, + "rss_peak_mb": 183.46875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.972958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "multiple_sheets", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.416292, + "p50": 0.521166, + "p95": 0.685792 + }, + "cpu_ms": { + "min": 0.857, + "p50": 1.196, + "p95": 1.744 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.521166, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "multiple_sheets", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.249459, + "p50": 1.3145, + "p95": 1.3485 + }, + "cpu_ms": { + "min": 1.25, + "p50": 1.314, + "p95": 1.349 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.3145, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.598167, + "p50": 1.713333, + "p95": 2.515416 + }, + "cpu_ms": { + "min": 1.598, + "p50": 1.713, + "p95": 2.008 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.713333, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.136667, + "p50": 1.191958, + "p95": 1.228417 + }, + "cpu_ms": { + "min": 1.136, + "p50": 1.192, + "p95": 1.228 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.191958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.241084, + "p50": 1.284958, + "p95": 1.321875 + }, + "cpu_ms": { + "min": 1.242, + "p50": 1.284, + "p95": 1.323 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.284958, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.464167, + "p50": 1.494667, + "p95": 2.036 + }, + "cpu_ms": { + "min": 1.464, + "p50": 1.496, + "p95": 2.036 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.494667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "merged_cells", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.052417, + "p50": 0.053292, + "p95": 0.059084 + }, + "cpu_ms": { + "min": 0.052, + "p50": 0.053, + "p95": 0.06 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.053292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "merged_cells", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.773917, + "p50": 0.795292, + "p95": 0.870791 + }, + "cpu_ms": { + "min": 0.774, + "p50": 0.795, + "p95": 0.871 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.795292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.062125, + "p50": 1.104542, + "p95": 1.372625 + }, + "cpu_ms": { + "min": 1.062, + "p50": 1.105, + "p95": 1.372 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.104542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.855125, + "p50": 0.928667, + "p95": 0.948375 + }, + "cpu_ms": { + "min": 0.855, + "p50": 0.929, + "p95": 0.949 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.928667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature" + }, + { + "feature": "merged_cells", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "merged_cells", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.197583, + "p50": 1.266084, + "p95": 1.30475 + }, + "cpu_ms": { + "min": 1.199, + "p50": 1.266, + "p95": 1.305 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.266084, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature" + }, + { + "feature": "merged_cells", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.171917, + "p50": 0.178625, + "p95": 0.191125 + }, + "cpu_ms": { + "min": 0.173, + "p50": 0.179, + "p95": 0.191 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.178625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "merged_cells", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.181416, + "p50": 1.258209, + "p95": 1.283958 + }, + "cpu_ms": { + "min": 1.181, + "p50": 1.259, + "p95": 1.284 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.258209, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.270208, + "p50": 1.351917, + "p95": 1.426833 + }, + "cpu_ms": { + "min": 1.27, + "p50": 1.352, + "p95": 1.427 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.351917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "merged_cells", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.44825, + "p50": 1.486208, + "p95": 1.942959 + }, + "cpu_ms": { + "min": 1.449, + "p50": 1.486, + "p95": 1.943 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.486208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "merged_cells", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.79575, + "p50": 0.862959, + "p95": 0.883875 + }, + "cpu_ms": { + "min": 0.796, + "p50": 0.864, + "p95": 0.884 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.862959, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "merged_cells", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.188584, + "p50": 0.229292, + "p95": 0.273958 + }, + "cpu_ms": { + "min": 0.286, + "p50": 0.43, + "p95": 0.626 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.229292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "merged_cells", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.969625, + "p50": 1.04675, + "p95": 1.061708 + }, + "cpu_ms": { + "min": 0.97, + "p50": 1.048, + "p95": 1.061 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.04675, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.099208, + "p50": 1.12825, + "p95": 1.220834 + }, + "cpu_ms": { + "min": 1.099, + "p50": 1.128, + "p95": 1.222 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.12825, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.309, + "p50": 1.347416, + "p95": 1.397334 + }, + "cpu_ms": { + "min": 1.309, + "p50": 1.347, + "p95": 1.397 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.347416, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.558458, + "p50": 1.591708, + "p95": 1.761958 + }, + "cpu_ms": { + "min": 1.558, + "p50": 1.592, + "p95": 1.762 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.591708, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.535875, + "p50": 1.615125, + "p95": 2.082625 + }, + "cpu_ms": { + "min": 1.536, + "p50": 1.616, + "p95": 2.083 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.615125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "conditional_formatting", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.04675, + "p50": 0.047625, + "p95": 0.052416 + }, + "cpu_ms": { + "min": 0.046, + "p50": 0.048, + "p95": 0.052 + }, + "rss_peak_mb": 183.59375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.047625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "conditional_formatting", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.9745, + "p50": 0.98925, + "p95": 1.038125 + }, + "cpu_ms": { + "min": 0.974, + "p50": 0.988, + "p95": 1.038 + }, + "rss_peak_mb": 183.640625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.98925, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.185, + "p50": 1.223458, + "p95": 1.276833 + }, + "cpu_ms": { + "min": 1.184, + "p50": 1.224, + "p95": 1.277 + }, + "rss_peak_mb": 183.703125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.223458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_conditional_format: pylightxl does not implement this feature" + }, + { + "feature": "conditional_formatting", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "conditional_formatting", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.408833, + "p50": 1.453541, + "p95": 1.598542 + }, + "cpu_ms": { + "min": 1.409, + "p50": 1.453, + "p95": 1.59 + }, + "rss_peak_mb": 184.15625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.453541, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_conditional_format: pyexcel does not expose this worksheet feature" + }, + { + "feature": "conditional_formatting", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_conditional_format: xlwt cannot author conditional formatting" + }, + { + "feature": "conditional_formatting", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.672375, + "p50": 1.708541, + "p95": 1.728209 + }, + "cpu_ms": { + "min": 1.671, + "p50": 1.709, + "p95": 1.728 + }, + "rss_peak_mb": 184.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.708541, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.37, + "p50": 1.43175, + "p95": 1.563375 + }, + "cpu_ms": { + "min": 1.37, + "p50": 1.432, + "p95": 1.564 + }, + "rss_peak_mb": 184.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.43175, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "conditional_formatting", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.6475, + "p50": 1.719, + "p95": 2.144291 + }, + "cpu_ms": { + "min": 1.648, + "p50": 1.719, + "p95": 2.145 + }, + "rss_peak_mb": 184.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.719, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "conditional_formatting", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.837667, + "p50": 0.909042, + "p95": 0.952708 + }, + "cpu_ms": { + "min": 0.838, + "p50": 0.909, + "p95": 0.953 + }, + "rss_peak_mb": 184.390625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.909042, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "conditional_formatting", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.311333, + "p50": 0.358292, + "p95": 0.497667 + }, + "cpu_ms": { + "min": 0.515, + "p50": 0.854, + "p95": 1.213 + }, + "rss_peak_mb": 184.40625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.358292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "conditional_formatting", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.354542, + "p50": 1.378667, + "p95": 1.410333 + }, + "cpu_ms": { + "min": 1.356, + "p50": 1.379, + "p95": 1.411 + }, + "rss_peak_mb": 184.40625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.378667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.28075, + "p50": 1.322791, + "p95": 1.439459 + }, + "cpu_ms": { + "min": 1.281, + "p50": 1.322, + "p95": 1.44 + }, + "rss_peak_mb": 184.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.322791, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.170334, + "p50": 1.1965, + "p95": 1.244166 + }, + "cpu_ms": { + "min": 1.171, + "p50": 1.197, + "p95": 1.245 + }, + "rss_peak_mb": 184.53125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.1965, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.137583, + "p50": 1.190167, + "p95": 1.341875 + }, + "cpu_ms": { + "min": 1.137, + "p50": 1.19, + "p95": 1.343 + }, + "rss_peak_mb": 184.53125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.190167, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.323792, + "p50": 1.410667, + "p95": 1.769583 + }, + "cpu_ms": { + "min": 1.323, + "p50": 1.411, + "p95": 1.77 + }, + "rss_peak_mb": 184.53125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.410667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "data_validation", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.045875, + "p50": 0.046334, + "p95": 0.051209 + }, + "cpu_ms": { + "min": 0.045, + "p50": 0.047, + "p95": 0.051 + }, + "rss_peak_mb": 184.53125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.046334, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "data_validation", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.5515, + "p50": 0.577458, + "p95": 0.637875 + }, + "cpu_ms": { + "min": 0.552, + "p50": 0.577, + "p95": 0.638 + }, + "rss_peak_mb": 184.5625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.577458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.044958, + "p50": 1.075375, + "p95": 1.11375 + }, + "cpu_ms": { + "min": 1.044, + "p50": 1.076, + "p95": 1.114 + }, + "rss_peak_mb": 184.578125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.075375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_data_validation: pylightxl does not implement this feature" + }, + { + "feature": "data_validation", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "data_validation", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.2795, + "p50": 1.309583, + "p95": 1.624542 + }, + "cpu_ms": { + "min": 1.279, + "p50": 1.31, + "p95": 1.624 + }, + "rss_peak_mb": 184.828125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.309583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_data_validation: pyexcel does not expose this worksheet feature" + }, + { + "feature": "data_validation", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_data_validation: xlwt cannot author data validations" + }, + { + "feature": "data_validation", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.574959, + "p50": 1.61275, + "p95": 1.746666 + }, + "cpu_ms": { + "min": 1.575, + "p50": 1.613, + "p95": 1.747 + }, + "rss_peak_mb": 184.828125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.61275, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.129666, + "p50": 1.181125, + "p95": 1.254041 + }, + "cpu_ms": { + "min": 1.13, + "p50": 1.181, + "p95": 1.254 + }, + "rss_peak_mb": 184.828125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.181125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "data_validation", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.404792, + "p50": 1.460042, + "p95": 1.850458 + }, + "cpu_ms": { + "min": 1.405, + "p50": 1.46, + "p95": 1.851 + }, + "rss_peak_mb": 184.828125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.460042, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "data_validation", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.783083, + "p50": 0.852375, + "p95": 0.916875 + }, + "cpu_ms": { + "min": 0.784, + "p50": 0.852, + "p95": 0.917 + }, + "rss_peak_mb": 184.828125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.852375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "data_validation", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.428875, + "p50": 0.511333, + "p95": 0.690917 + }, + "cpu_ms": { + "min": 1.256, + "p50": 1.875, + "p95": 2.563 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.511333, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "data_validation", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.194958, + "p50": 1.322833, + "p95": 1.475083 + }, + "cpu_ms": { + "min": 1.195, + "p50": 1.324, + "p95": 1.475 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.322833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.0195, + "p50": 1.054917, + "p95": 1.1035 + }, + "cpu_ms": { + "min": 1.02, + "p50": 1.054, + "p95": 1.104 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.054917, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.108208, + "p50": 1.140916, + "p95": 1.174708 + }, + "cpu_ms": { + "min": 1.109, + "p50": 1.142, + "p95": 1.175 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.140916, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.129208, + "p50": 1.175125, + "p95": 1.206875 + }, + "cpu_ms": { + "min": 1.129, + "p50": 1.175, + "p95": 1.207 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.175125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.583166, + "p50": 1.679125, + "p95": 2.124042 + }, + "cpu_ms": { + "min": 1.584, + "p50": 1.679, + "p95": 2.124 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.679125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "hyperlinks", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.045916, + "p50": 0.046583, + "p95": 0.04775 + }, + "cpu_ms": { + "min": 0.045, + "p50": 0.046, + "p95": 0.048 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.046583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "hyperlinks", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.097083, + "p50": 1.115083, + "p95": 1.17175 + }, + "cpu_ms": { + "min": 1.098, + "p50": 1.114, + "p95": 1.171 + }, + "rss_peak_mb": 185.046875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.115083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.106167, + "p50": 1.13, + "p95": 1.281792 + }, + "cpu_ms": { + "min": 1.106, + "p50": 1.13, + "p95": 1.281 + }, + "rss_peak_mb": 185.0625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.13, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature" + }, + { + "feature": "hyperlinks", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "hyperlinks", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.225958, + "p50": 1.261625, + "p95": 1.351458 + }, + "cpu_ms": { + "min": 1.226, + "p50": 1.262, + "p95": 1.351 + }, + "rss_peak_mb": 185.0625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.261625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature" + }, + { + "feature": "hyperlinks", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_hyperlink: xlwt hyperlink metadata is not supported in this adapter" + }, + { + "feature": "hyperlinks", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.434625, + "p50": 1.510167, + "p95": 1.551833 + }, + "cpu_ms": { + "min": 1.434, + "p50": 1.51, + "p95": 1.552 + }, + "rss_peak_mb": 185.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.510167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.117834, + "p50": 1.190625, + "p95": 1.31675 + }, + "cpu_ms": { + "min": 1.118, + "p50": 1.191, + "p95": 1.316 + }, + "rss_peak_mb": 185.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.190625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "hyperlinks", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.582167, + "p50": 1.683584, + "p95": 1.8925 + }, + "cpu_ms": { + "min": 1.582, + "p50": 1.684, + "p95": 1.892 + }, + "rss_peak_mb": 185.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.683584, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "hyperlinks", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.810583, + "p50": 0.888458, + "p95": 1.020583 + }, + "cpu_ms": { + "min": 0.81, + "p50": 0.888, + "p95": 1.012 + }, + "rss_peak_mb": 185.078125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.888458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "hyperlinks", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.305875, + "p50": 0.357083, + "p95": 0.477666 + }, + "cpu_ms": { + "min": 0.643, + "p50": 0.784, + "p95": 1.328 + }, + "rss_peak_mb": 185.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.357083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "hyperlinks", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.129667, + "p50": 1.206125, + "p95": 1.280458 + }, + "cpu_ms": { + "min": 1.129, + "p50": 1.206, + "p95": 1.275 + }, + "rss_peak_mb": 185.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.206125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.026709, + "p50": 1.078125, + "p95": 1.149667 + }, + "cpu_ms": { + "min": 1.027, + "p50": 1.079, + "p95": 1.149 + }, + "rss_peak_mb": 185.1875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.078125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.033292, + "p50": 1.096208, + "p95": 1.167834 + }, + "cpu_ms": { + "min": 1.033, + "p50": 1.097, + "p95": 1.168 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.096208, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.583375, + "p50": 1.654542, + "p95": 1.760167 + }, + "cpu_ms": { + "min": 1.584, + "p50": 1.646, + "p95": 1.751 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.654542, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 2.2315, + "p50": 2.319667, + "p95": 2.80025 + }, + "cpu_ms": { + "min": 2.232, + "p50": 2.295, + "p95": 2.8 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.319667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "images", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.047791, + "p50": 0.04825, + "p95": 0.053417 + }, + "cpu_ms": { + "min": 0.047, + "p50": 0.049, + "p95": 0.053 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.04825, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "images", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.827375, + "p50": 0.846209, + "p95": 0.900291 + }, + "cpu_ms": { + "min": 0.827, + "p50": 0.846, + "p95": 0.9 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.846209, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.37675, + "p50": 1.423792, + "p95": 1.55475 + }, + "cpu_ms": { + "min": 1.376, + "p50": 1.424, + "p95": 1.554 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.423792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_image: pylightxl does not implement this feature" + }, + { + "feature": "images", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "images", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.116083, + "p50": 1.16775, + "p95": 1.236459 + }, + "cpu_ms": { + "min": 1.116, + "p50": 1.167, + "p95": 1.236 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.16775, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_image: pyexcel does not expose this worksheet feature" + }, + { + "feature": "images", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_image: xlwt cannot embed images in this adapter" + }, + { + "feature": "images", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.03375, + "p50": 1.106083, + "p95": 1.145084 + }, + "cpu_ms": { + "min": 1.034, + "p50": 1.107, + "p95": 1.145 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.106083, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.114333, + "p50": 1.168583, + "p95": 1.242 + }, + "cpu_ms": { + "min": 1.114, + "p50": 1.169, + "p95": 1.243 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.168583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "images", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.337375, + "p50": 1.391583, + "p95": 1.816625 + }, + "cpu_ms": { + "min": 1.338, + "p50": 1.391, + "p95": 1.817 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.391583, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "images", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.714958, + "p50": 0.769667, + "p95": 0.811333 + }, + "cpu_ms": { + "min": 0.715, + "p50": 0.769, + "p95": 0.81 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.769667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "images", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.184167, + "p50": 0.215833, + "p95": 0.273042 + }, + "cpu_ms": { + "min": 0.276, + "p50": 0.39, + "p95": 0.691 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.215833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "images", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.864625, + "p50": 0.92575, + "p95": 0.946334 + }, + "cpu_ms": { + "min": 0.866, + "p50": 0.926, + "p95": 0.946 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.92575, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.015875, + "p50": 1.056708, + "p95": 1.133958 + }, + "cpu_ms": { + "min": 1.016, + "p50": 1.057, + "p95": 1.134 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.056708, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.770209, + "p50": 0.805583, + "p95": 0.840875 + }, + "cpu_ms": { + "min": 0.77, + "p50": 0.805, + "p95": 0.841 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.805583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.031959, + "p50": 1.076792, + "p95": 1.130875 + }, + "cpu_ms": { + "min": 1.033, + "p50": 1.077, + "p95": 1.13 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.076792, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.258292, + "p50": 1.307375, + "p95": 1.6915 + }, + "cpu_ms": { + "min": 1.258, + "p50": 1.307, + "p95": 1.692 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.307375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "pivot_tables", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.048625, + "p50": 0.049125, + "p95": 0.054292 + }, + "cpu_ms": { + "min": 0.048, + "p50": 0.049, + "p95": 0.054 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.049125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "pivot_tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.445792, + "p50": 0.466417, + "p95": 0.513625 + }, + "cpu_ms": { + "min": 0.446, + "p50": 0.467, + "p95": 0.514 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.466417, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.005375, + "p50": 1.02975, + "p95": 1.118125 + }, + "cpu_ms": { + "min": 1.005, + "p50": 1.03, + "p95": 1.119 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.02975, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.683125, + "p50": 0.765958, + "p95": 0.829084 + }, + "cpu_ms": { + "min": 0.683, + "p50": 0.765, + "p95": 0.822 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.765958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 0.195417, + "p50": 0.200625, + "p95": 0.210208 + }, + "cpu_ms": { + "min": 0.195, + "p50": 0.201, + "p95": 0.209 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.200625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "pivot_tables", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.819583, + "p50": 0.876583, + "p95": 0.922167 + }, + "cpu_ms": { + "min": 0.82, + "p50": 0.877, + "p95": 0.922 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.876583, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.035917, + "p50": 1.081083, + "p95": 1.127292 + }, + "cpu_ms": { + "min": 1.035, + "p50": 1.081, + "p95": 1.128 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.081083, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.120083, + "p50": 0.123959, + "p95": 0.132083 + }, + "cpu_ms": { + "min": 0.12, + "p50": 0.124, + "p95": 0.132 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.123959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "pivot_tables", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.967291, + "p50": 1.031375, + "p95": 1.07575 + }, + "cpu_ms": { + "min": 0.967, + "p50": 1.032, + "p95": 1.076 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.031375, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.146292, + "p50": 1.18425, + "p95": 1.272167 + }, + "cpu_ms": { + "min": 1.147, + "p50": 1.185, + "p95": 1.252 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.18425, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "pivot_tables", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.3365, + "p50": 1.390875, + "p95": 1.908709 + }, + "cpu_ms": { + "min": 1.336, + "p50": 1.39, + "p95": 1.909 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.390875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "pivot_tables", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.660375, + "p50": 0.690291, + "p95": 0.750375 + }, + "cpu_ms": { + "min": 0.66, + "p50": 0.69, + "p95": 0.75 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.690291, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "pivot_tables", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.168583, + "p50": 0.202167, + "p95": 0.251375 + }, + "cpu_ms": { + "min": 0.224, + "p50": 0.325, + "p95": 0.374 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.202167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "pivot_tables", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.757834, + "p50": 0.821125, + "p95": 0.847833 + }, + "cpu_ms": { + "min": 0.758, + "p50": 0.821, + "p95": 0.849 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.821125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.019709, + "p50": 1.0535, + "p95": 1.115625 + }, + "cpu_ms": { + "min": 1.02, + "p50": 1.053, + "p95": 1.115 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.0535, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.010542, + "p50": 1.0675, + "p95": 1.086708 + }, + "cpu_ms": { + "min": 1.011, + "p50": 1.067, + "p95": 1.087 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.0675, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.304042, + "p50": 1.345458, + "p95": 1.447666 + }, + "cpu_ms": { + "min": 1.304, + "p50": 1.345, + "p95": 1.441 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.345458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.703625, + "p50": 1.765709, + "p95": 2.268625 + }, + "cpu_ms": { + "min": 1.704, + "p50": 1.766, + "p95": 2.227 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.765709, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "comments", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.053875, + "p50": 0.054667, + "p95": 0.059209 + }, + "cpu_ms": { + "min": 0.053, + "p50": 0.055, + "p95": 0.059 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.054667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "comments", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.08975, + "p50": 1.106709, + "p95": 1.185583 + }, + "cpu_ms": { + "min": 1.089, + "p50": 1.107, + "p95": 1.186 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.106709, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.193208, + "p50": 1.20525, + "p95": 1.270041 + }, + "cpu_ms": { + "min": 1.193, + "p50": 1.205, + "p95": 1.27 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.20525, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.056666, + "p50": 1.075667, + "p95": 1.096416 + }, + "cpu_ms": { + "min": 1.057, + "p50": 1.076, + "p95": 1.097 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.075667, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature" + }, + { + "feature": "comments", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "comments", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.072708, + "p50": 1.132833, + "p95": 1.274833 + }, + "cpu_ms": { + "min": 1.072, + "p50": 1.133, + "p95": 1.274 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.132833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature" + }, + { + "feature": "comments", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read unsupported; Write failed: UnsupportedAdapterOperationError: xlwt does not support add_comment: xlwt cannot author comments" + }, + { + "feature": "comments", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.106, + "p50": 1.172459, + "p95": 1.21775 + }, + "cpu_ms": { + "min": 1.105, + "p50": 1.172, + "p95": 1.217 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.172459, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.1575, + "p50": 1.216375, + "p95": 1.282417 + }, + "cpu_ms": { + "min": 1.158, + "p50": 1.216, + "p95": 1.283 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.216375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "comments", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.3315, + "p50": 1.359292, + "p95": 1.622916 + }, + "cpu_ms": { + "min": 1.332, + "p50": 1.359, + "p95": 1.623 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.359292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "comments", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.781042, + "p50": 0.840167, + "p95": 0.884291 + }, + "cpu_ms": { + "min": 0.78, + "p50": 0.84, + "p95": 0.885 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.840167, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "comments", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.196167, + "p50": 0.22575, + "p95": 0.270166 + }, + "cpu_ms": { + "min": 0.296, + "p50": 0.417, + "p95": 0.565 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.22575, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "comments", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.895792, + "p50": 0.968875, + "p95": 1.017333 + }, + "cpu_ms": { + "min": 0.896, + "p50": 0.969, + "p95": 1.017 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.968875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.033541, + "p50": 1.070833, + "p95": 1.273916 + }, + "cpu_ms": { + "min": 1.034, + "p50": 1.07, + "p95": 1.125 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.070833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.3035, + "p50": 1.33325, + "p95": 1.362125 + }, + "cpu_ms": { + "min": 1.304, + "p50": 1.333, + "p95": 1.362 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.33325, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.784208, + "p50": 1.846916, + "p95": 2.033458 + }, + "cpu_ms": { + "min": 1.784, + "p50": 1.847, + "p95": 2.025 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.846916, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.70325, + "p50": 1.751208, + "p95": 2.267084 + }, + "cpu_ms": { + "min": 1.702, + "p50": 1.751, + "p95": 2.267 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.751208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "freeze_panes", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.047375, + "p50": 0.04825, + "p95": 0.05375 + }, + "cpu_ms": { + "min": 0.047, + "p50": 0.048, + "p95": 0.054 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.04825, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "freeze_panes", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.628917, + "p50": 0.665333, + "p95": 0.706292 + }, + "cpu_ms": { + "min": 0.629, + "p50": 0.665, + "p95": 0.707 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.665333, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.254875, + "p50": 1.304375, + "p95": 1.485667 + }, + "cpu_ms": { + "min": 1.254, + "p50": 1.304, + "p95": 1.451 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.304375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'; Write failed: UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature" + }, + { + "feature": "freeze_panes", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "freeze_panes", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.404459, + "p50": 1.448625, + "p95": 1.519875 + }, + "cpu_ms": { + "min": 1.405, + "p50": 1.448, + "p95": 1.519 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.448625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write failed: UnsupportedAdapterOperationError: pyexcel does not support set_freeze_panes: pyexcel does not expose this worksheet feature" + }, + { + "feature": "freeze_panes", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.173042, + "p50": 0.182833, + "p95": 0.197917 + }, + "cpu_ms": { + "min": 0.172, + "p50": 0.183, + "p95": 0.198 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.182833, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "freeze_panes", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.688, + "p50": 1.732584, + "p95": 1.877458 + }, + "cpu_ms": { + "min": 1.689, + "p50": 1.732, + "p95": 1.877 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.732584, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.918375, + "p50": 2.000125, + "p95": 2.277333 + }, + "cpu_ms": { + "min": 1.918, + "p50": 2.0, + "p95": 2.213 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.000125, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "freeze_panes", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.934292, + "p50": 2.007459, + "p95": 2.604708 + }, + "cpu_ms": { + "min": 1.934, + "p50": 2.007, + "p95": 2.605 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 2.007459, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "freeze_panes", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.876209, + "p50": 0.947791, + "p95": 0.993958 + }, + "cpu_ms": { + "min": 0.876, + "p50": 0.948, + "p95": 0.994 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.947791, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "freeze_panes", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.370334, + "p50": 0.439542, + "p95": 0.520458 + }, + "cpu_ms": { + "min": 0.551, + "p50": 0.989, + "p95": 1.305 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.439542, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "freeze_panes", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.339417, + "p50": 1.360458, + "p95": 1.414291 + }, + "cpu_ms": { + "min": 1.339, + "p50": 1.361, + "p95": 1.415 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.360458, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.783583, + "p50": 1.808959, + "p95": 2.014916 + }, + "cpu_ms": { + "min": 1.784, + "p50": 1.808, + "p95": 1.876 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.808959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.032667, + "p50": 1.08575, + "p95": 1.125334 + }, + "cpu_ms": { + "min": 1.032, + "p50": 1.086, + "p95": 1.126 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.08575, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.243625, + "p50": 1.367875, + "p95": 1.476167 + }, + "cpu_ms": { + "min": 1.244, + "p50": 1.368, + "p95": 1.476 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.367875, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.434041, + "p50": 1.652041, + "p95": 2.198167 + }, + "cpu_ms": { + "min": 1.434, + "p50": 1.652, + "p95": 2.183 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.652041, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "named_ranges", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.04475, + "p50": 0.045292, + "p95": 0.048542 + }, + "cpu_ms": { + "min": 0.044, + "p50": 0.045, + "p95": 0.049 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.045292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "named_ranges", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.447375, + "p50": 0.470875, + "p95": 0.524333 + }, + "cpu_ms": { + "min": 0.448, + "p50": 0.471, + "p95": 0.524 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.470875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.086, + "p50": 1.127291, + "p95": 1.191042 + }, + "cpu_ms": { + "min": 1.086, + "p50": 1.128, + "p95": 1.191 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.127291, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.218542, + "p50": 0.225625, + "p95": 0.233334 + }, + "cpu_ms": { + "min": 0.218, + "p50": 0.226, + "p95": 0.233 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.225625, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'" + }, + { + "feature": "named_ranges", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "named_ranges", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.17025, + "p50": 1.19925, + "p95": 1.433416 + }, + "cpu_ms": { + "min": 1.169, + "p50": 1.199, + "p95": 1.433 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.19925, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.331417, + "p50": 1.389667, + "p95": 1.506458 + }, + "cpu_ms": { + "min": 1.332, + "p50": 1.39, + "p95": 1.506 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.389667, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.145958, + "p50": 0.148959, + "p95": 0.158916 + }, + "cpu_ms": { + "min": 0.146, + "p50": 0.149, + "p95": 0.158 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.148959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "named_ranges", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.388667, + "p50": 1.450958, + "p95": 1.510334 + }, + "cpu_ms": { + "min": 1.388, + "p50": 1.451, + "p95": 1.511 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.450958, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.419917, + "p50": 1.457959, + "p95": 1.511833 + }, + "cpu_ms": { + "min": 1.419, + "p50": 1.459, + "p95": 1.512 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.457959, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "named_ranges", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.526417, + "p50": 1.573417, + "p95": 1.809875 + }, + "cpu_ms": { + "min": 1.527, + "p50": 1.573, + "p95": 1.809 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.573417, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "named_ranges", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.77925, + "p50": 0.848459, + "p95": 0.871333 + }, + "cpu_ms": { + "min": 0.779, + "p50": 0.849, + "p95": 0.871 + }, + "rss_peak_mb": 186.234375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.848459, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "named_ranges", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.303375, + "p50": 0.407625, + "p95": 0.4955 + }, + "cpu_ms": { + "min": 0.807, + "p50": 1.149, + "p95": 1.724 + }, + "rss_peak_mb": 186.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.407625, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "named_ranges", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.082583, + "p50": 1.150333, + "p95": 1.167042 + }, + "cpu_ms": { + "min": 1.081, + "p50": 1.15, + "p95": 1.167 + }, + "rss_peak_mb": 186.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.150333, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.279208, + "p50": 1.332375, + "p95": 1.438333 + }, + "cpu_ms": { + "min": 1.279, + "p50": 1.332, + "p95": 1.438 + }, + "rss_peak_mb": 186.265625, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.332375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "openpyxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.358958, + "p50": 1.395542, + "p95": 1.436375 + }, + "cpu_ms": { + "min": 1.359, + "p50": 1.396, + "p95": 1.436 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.395542, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.047125, + "p50": 1.082416, + "p95": 1.131625 + }, + "cpu_ms": { + "min": 1.046, + "p50": 1.083, + "p95": 1.132 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.082416, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlsxwriter", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.289875, + "p50": 1.331208, + "p95": 1.704417 + }, + "cpu_ms": { + "min": 1.29, + "p50": 1.331, + "p95": 1.705 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.331208, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "tables", + "library": "python-calamine", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.048541, + "p50": 0.049042, + "p95": 0.054542 + }, + "cpu_ms": { + "min": 0.048, + "p50": 0.05, + "p95": 0.054 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.049042, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "tables", + "library": "wolfxl", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.488292, + "p50": 0.505292, + "p95": 0.528041 + }, + "cpu_ms": { + "min": 0.488, + "p50": 0.506, + "p95": 0.528 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.505292, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.002084, + "p50": 1.037584, + "p95": 1.066416 + }, + "cpu_ms": { + "min": 1.002, + "p50": 1.038, + "p95": 1.067 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.037584, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "pylightxl", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.195209, + "p50": 0.203292, + "p95": 0.223958 + }, + "cpu_ms": { + "min": 0.195, + "p50": 0.203, + "p95": 0.224 + }, + "rss_peak_mb": 186.4375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.203292, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read failed: TypeError: expected string or bytes-like object, got 'NoneType'" + }, + { + "feature": "tables", + "library": "xlrd", + "workload_size": "small", + "perf": { + "read": null, + "write": null + }, + "notes": "Write unsupported; Read not applicable: xlrd does not support .xlsx input" + }, + { + "feature": "tables", + "library": "pyexcel", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.691125, + "p50": 1.720291, + "p95": 2.0175 + }, + "cpu_ms": { + "min": 1.691, + "p50": 1.72, + "p95": 2.017 + }, + "rss_peak_mb": 186.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.720291, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.061792, + "p50": 1.110916, + "p95": 1.731792 + }, + "cpu_ms": { + "min": 1.062, + "p50": 1.111, + "p95": 1.263 + }, + "rss_peak_mb": 186.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.110916, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlwt", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 0.125792, + "p50": 0.129458, + "p95": 0.133459 + }, + "cpu_ms": { + "min": 0.126, + "p50": 0.13, + "p95": 0.133 + }, + "rss_peak_mb": 186.859375, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 0.129458, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "tables", + "library": "pandas", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.594042, + "p50": 1.607792, + "p95": 1.677041 + }, + "cpu_ms": { + "min": 1.594, + "p50": 1.608, + "p95": 1.677 + }, + "rss_peak_mb": 186.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.607792, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.141209, + "p50": 1.196375, + "p95": 1.2465 + }, + "cpu_ms": { + "min": 1.141, + "p50": 1.197, + "p95": 1.246 + }, + "rss_peak_mb": 186.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.196375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "xlsxwriter-constmem", + "workload_size": "small", + "perf": { + "read": null, + "write": { + "wall_ms": { + "min": 1.313125, + "p50": 1.378416, + "p95": 1.792416 + }, + "cpu_ms": { + "min": 1.313, + "p50": 1.379, + "p95": 1.792 + }, + "rss_peak_mb": 186.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.378416, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": "Read unsupported" + }, + { + "feature": "tables", + "library": "openpyxl-readonly", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.860834, + "p50": 0.902875, + "p95": 1.046458 + }, + "cpu_ms": { + "min": 0.861, + "p50": 0.903, + "p95": 1.047 + }, + "rss_peak_mb": 186.875, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.902875, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "tables", + "library": "polars", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 0.315, + "p50": 0.370833, + "p95": 0.475916 + }, + "cpu_ms": { + "min": 1.067, + "p50": 1.555, + "p95": 2.164 + }, + "rss_peak_mb": 187.3125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.370833, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": null + }, + "notes": "Write unsupported" + }, + { + "feature": "tables", + "library": "tablib", + "workload_size": "small", + "perf": { + "read": { + "wall_ms": { + "min": 1.29525, + "p50": 1.331125, + "p95": 1.459167 + }, + "cpu_ms": { + "min": 1.295, + "p50": 1.331, + "p95": 1.46 + }, + "rss_peak_mb": 187.3125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 1.331125, + "write": 0.0, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + }, + "write": { + "wall_ms": { + "min": 1.028042, + "p50": 1.082375, + "p95": 1.119875 + }, + "cpu_ms": { + "min": 1.028, + "p50": 1.082, + "p95": 1.12 + }, + "rss_peak_mb": 187.3125, + "breakdown_ms": null, + "phase_attribution_ms": { + "parse": 0.0, + "write": 1.082375, + "verify": 0.0 + }, + "op_count": null, + "op_unit": null, + "rss_kb_via_time": null, + "python_heap_peak_kb": null + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/results-2026-10-02/perf/run-log.txt b/results-2026-10-02/perf/run-log.txt new file mode 100644 index 0000000..a3e85ea --- /dev/null +++ b/results-2026-10-02/perf/run-log.txt @@ -0,0 +1,76 @@ +gate_check 08:32:30Z load1=7.59 +gate_check 08:32:40Z load1=6.81 +gate_check 08:32:50Z load1=6.21 +gate_check 08:33:01Z load1=5.56 +gate_check 08:33:11Z load1=4.86 +gate_check 08:33:21Z load1=4.43 +gate_check 08:33:31Z load1=4.05 +gate_check 08:33:41Z load1=3.81 +start_utc 2026-10-02T08:33:41Z +load_before { 3.81 3.75 2.87 } + %CPU COMM + 97.2 [background agent process, path redacted] + 5.8 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Support/mdworker_shared + 2.5 /System/Library/PrivateFrameworks/SkyLight.framework/Resources/WindowServer +CMD: excelbench perf --tests fixtures/excel --output ../out --profile xlsx --warmup 3 --iters 25 --iteration-policy fixed --memory-mode getrusage --feature cell_values --feature formulas --feature text_formatting --feature background_colors --feature number_formats --feature alignment --feature borders --feature dimensions --feature multiple_sheets --feature merged_cells --feature conditional_formatting --feature data_validation --feature hyperlinks --feature images --feature pivot_tables --feature comments --feature freeze_panes --feature named_ranges --feature tables --adapter openpyxl --adapter xlsxwriter --adapter python-calamine --adapter wolfxl --adapter pylightxl --adapter xlrd --adapter pyexcel --adapter xlwt --adapter pandas --adapter xlsxwriter-constmem --adapter openpyxl-readonly --adapter polars --adapter tablib +Running performance benchmark... + Profile: xlsx + Test files: fixtures/excel + Output: ../out/perf + Warmup: 3 + Iterations: 25 + Iteration policy: fixed + Breakdown: False + Memory mode: getrusage + Adapters: openpyxl, xlsxwriter, python-calamine, wolfxl, pylightxl, xlrd, +pyexcel, xlwt, pandas, xlsxwriter-constmem, openpyxl-readonly, polars, tablib + +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +~/wolf-lane/officelibs-perf/venv/lib/python3.12/site-packages/excelbench/harness/adapters/polars_adapter.py:97: FutureWarning: from_arrow() will return a Series instead of a DataFrame in 2.0. To avoid this warning, pass the ArrowStreamExportable to either `pl.DataFrame` or `pl.Series` instead based on your desired output type. + frames = pl.read_excel( +✓ Performance results written to ../out/perf + - ../out/perf/results.json + - ../out/perf/README.md + - ../out/perf/matrix.csv + - ../out/perf/history.jsonl +real 13.11 +user 10.49 +sys 2.66 +exit_code 0 +load_after { 3.62 3.72 2.87 } +end_utc 2026-10-02T08:33:54Z diff --git a/results-2026-10-02/perf/run.sh b/results-2026-10-02/perf/run.sh new file mode 100755 index 0000000..db5b7f0 --- /dev/null +++ b/results-2026-10-02/perf/run.sh @@ -0,0 +1,23 @@ +#!/bin/zsh +set -u +cd "$HOME/wolf-lane/officelibs-perf/src" +F=(cell_values formulas text_formatting background_colors number_formats alignment borders dimensions multiple_sheets merged_cells conditional_formatting data_validation hyperlinks images pivot_tables comments freeze_panes named_ranges tables) +A=(openpyxl xlsxwriter python-calamine wolfxl pylightxl xlrd pyexcel xlwt pandas xlsxwriter-constmem openpyxl-readonly polars tablib) +args=() +for f in $F; do args+=(--feature $f); done +for a in $A; do args+=(--adapter $a); done +for i in $(seq 1 60); do + l1=$(sysctl -n vm.loadavg | awk "{print \$2}") + echo "gate_check $(date -u +%H:%M:%SZ) load1=$l1" + if (( l1 <= 4.0 )); then break; fi + sleep 10 +done +echo "start_utc $(date -u +%Y-%m-%dT%H:%M:%SZ)" +echo "load_before $(sysctl -n vm.loadavg)" +ps -Ao pcpu,comm -r | head -4 +echo "CMD: excelbench perf --tests fixtures/excel --output ../out --profile xlsx --warmup 3 --iters 25 --iteration-policy fixed --memory-mode getrusage ${args[*]}" +/usr/bin/time -p ../venv/bin/excelbench perf --tests fixtures/excel --output ../out --profile xlsx --warmup 3 --iters 25 --iteration-policy fixed --memory-mode getrusage "${args[@]}" +rc=$? +echo "exit_code $rc" +echo "load_after $(sysctl -n vm.loadavg)" +echo "end_utc $(date -u +%Y-%m-%dT%H:%M:%SZ)" diff --git a/results-2026-10-02/xlsx/FIDELITY_DELTAS.md b/results-2026-10-02/xlsx/FIDELITY_DELTAS.md new file mode 100644 index 0000000..a91d7e9 --- /dev/null +++ b/results-2026-10-02/xlsx/FIDELITY_DELTAS.md @@ -0,0 +1,3 @@ +# Fidelity Deltas + +Need at least two runs in history.jsonl. diff --git a/results-2026-10-02/xlsx/README.md b/results-2026-10-02/xlsx/README.md new file mode 100644 index 0000000..9b34a07 --- /dev/null +++ b/results-2026-10-02/xlsx/README.md @@ -0,0 +1,4704 @@ +# ExcelBench Results + +*Generated: 2026-10-02 06:55 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 | exceljs | libreoffice | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | sheetjs | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| Cell Values | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | +| Formulas | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🟢 | 🟢 | 🔴 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | +| Sheets | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟠 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | + +**Tier 1 — Formatting** + +| Feature | aspose-cells-foss | exceljs | libreoffice | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | sheetjs | tablib | wolfxl | xlsxwriter | xlsx-constmem | xlwt | +|---------|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| Alignment | 🟠 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟠 | 🟠 | 🟢 | +| Bg Colors | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | +| Borders | 🟠 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | +| Dimensions | 🟢 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🟢 | 🟢 | 🟠 | 🟠 | +| Num Fmt | 🟢 | 🟢 | 🟠 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🔴 | 🟢 | 🟢 | 🟢 | 🟢 | +| Text Fmt | 🟠 | 🟢 | 🟢 | 🟢 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🔴 | 🟢 | 🟢 | 🟢 | 🟠 | + +**Tier 2 — Advanced** + +| Feature | aspose-cells-foss | exceljs | libreoffice | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | sheetjs | 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 | exceljs | libreoffice | openpyxl | opxl-readonly | pandas | polars | pyexcel | pylightxl | calamine | sheetjs | 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 | 19/21 | Hybrid Rust+Python: openpyxl-compatible API with patch-mode modify | +| **A** | exceljs | R+W | Rewrite | 15/21 | 15/21 features with full fidelity | +| **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** | libreoffice | R+W | Rewrite | 12/21 | 12/21 features with full fidelity | +| **B** | xlsxwriter-constmem | W | No | 12/21 | Memory-optimized write — loses images, comments, row height | +| **B** | sheetjs | R+W | Rewrite | 9/21 | 9/21 features with full fidelity | +| **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) | exceljs (R) | exceljs (W) | libreoffice (R) | libreoffice (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) | sheetjs (R) | sheetjs (W) | 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 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟠 1 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | +| [formulas](#formulas-details) | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🔴 0 | 🟢 3 | 🔴 0 | 🟠 1 | 🟢 3 | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [multiple_sheets](#multiple_sheets-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | + +**Tier 1 — Formatting** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | exceljs (R) | exceljs (W) | libreoffice (R) | libreoffice (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) | sheetjs (R) | sheetjs (W) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [alignment](#alignment-details) | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 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 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟠 1 | +| [borders](#borders-details) | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟠 1 | +| [dimensions](#dimensions-details) | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟠 1 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟠 1 | 🟠 1 | +| [number_formats](#number_formats-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟠 1 | 🟠 1 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🟢 3 | +| [text_formatting](#text_formatting-details) | 🟠 1 | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 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) | exceljs (R) | exceljs (W) | libreoffice (R) | libreoffice (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) | sheetjs (R) | sheetjs (W) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [chart_anchor](#chart_anchor-details) | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🔴 0 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | +| [comments](#comments-details) | 🟢 3 | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🔴 0 | 🔴 0 | +| [conditional_formatting](#conditional_formatting-details) | 🟢 3 | 🟢 3 | 🟡 2 | 🟡 2 | 🟡 2 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [data_validation](#data_validation-details) | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🟡 2 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 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 | 🟢 3 | 🟡 2 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [hyperlinks](#hyperlinks-details) | 🔴 0 | 🟢 3 | 🔴 0 | 🟡 2 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [images](#images-details) | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 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 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟡 2 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🟢 3 | 🟢 3 | 🔴 0 | +| [page_setup](#page_setup-details) | 🟠 1 | 🔴 0 | 🔴 0 | 🔴 0 | 🟠 1 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 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 | 🟠 1 | 🟢 3 | 🔴 0 | 🟡 2 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | + +**Tier 3 — Workbook Metadata** + +| Feature | aspose-cells-foss (R) | aspose-cells-foss (W) | exceljs (R) | exceljs (W) | libreoffice (R) | libreoffice (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) | sheetjs (R) | sheetjs (W) | tablib (R) | tablib (W) | wolfxl (R) | wolfxl (W) | xlrd (R) | xlsxwriter (W) | xlsxwriter-constmem (W) | xlwt (W) | +|---------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------| +| [named_ranges](#named_ranges-details) | 🟡 2 | 🟢 3 | 🟡 2 | 🟡 2 | 🟢 3 | 🟢 3 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🟡 2 | 🟡 2 | ➖ | 🔴 0 | 🔴 0 | 🔴 0 | +| [tables](#tables-details) | 🟠 1 | 🟠 1 | 🔴 0 | 🟢 3 | 🟢 3 | 🟡 2 | 🟢 3 | 🟢 3 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🔴 0 | 🟡 2 | 🟢 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 | +| exceljs | R | 133 | 113 | 20 | 85% | 12/21 | +| exceljs | W | 133 | 123 | 10 | 92% | 15/21 | +| libreoffice | R | 133 | 115 | 18 | 86% | 12/21 | +| libreoffice | W | 133 | 113 | 20 | 85% | 12/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 | +| sheetjs | R | 133 | 55 | 78 | 41% | 9/21 | +| sheetjs | W | 133 | 52 | 81 | 39% | 8/21 | +| tablib | R | 133 | 22 | 111 | 17% | 2/21 | +| tablib | W | 133 | 26 | 107 | 20% | 3/21 | +| wolfxl | R | 133 | 131 | 2 | 98% | 19/21 | +| wolfxl | W | 133 | 129 | 4 | 97% | 18/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 +- **exceljs** v4.4.0 (javascript) - modify, read, write; modify: Rewrite +- **libreoffice** v26.8.0.3 (build bce0998afefdbc355585ca324285661a2170ba77) (cli) - modify, 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 +- **sheetjs** v0.20.3 (javascript) - modify, read, write; modify: Rewrite +- **tablib** v3.9.0 (python) - read, write; modify: Rebuild +- **wolfxl** v2.0.5 (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 | 920 | +| category | internal | 44 | +| category | invalid_input | 71 | +| category | unsupported_feature | 608 | +| severity | error | 1035 | +| severity | warning | 608 | + +### 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'} | +| cell_values | libreoffice | boolean_true | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'boolean', 'value': True}, actual={'type': 'formula', 'value': '=TRUE()'} | +| cell_values | libreoffice | boolean_false | read | data_mismatch | error | Expected values did not match actual values: expected={'type': 'boolean', 'value': False}, actual={'type': 'formula', 'value': '=FALSE()'} | +| 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 | +| formulas | sheetjs | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| formulas | exceljs | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| formulas | libreoffice | formula_cell_ref | read | internal | error | RuntimeError: Expected formula, got error | +| 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 | 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 | 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 | 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 | bold | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| text_formatting | pylightxl | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| 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 | bold | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| text_formatting | pyexcel | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| 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} | +| text_formatting | sheetjs | bold | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={} | +| text_formatting | sheetjs | bold | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | italic | read | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={} | +| text_formatting | sheetjs | italic | write | data_mismatch | error | Expected values did not match actual values: expected={'italic': True}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | underline_single | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={} | +| text_formatting | sheetjs | underline_single | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'single'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | underline_double | read | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={} | +| text_formatting | sheetjs | underline_double | write | data_mismatch | error | Expected values did not match actual values: expected={'underline': 'double'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | strikethrough | read | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={} | +| text_formatting | sheetjs | strikethrough | write | data_mismatch | error | Expected values did not match actual values: expected={'strikethrough': True}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | bold_italic | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={} | +| text_formatting | sheetjs | bold_italic | write | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'italic': True}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_size_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={} | +| text_formatting | sheetjs | font_size_8 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 8}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_size_14 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={} | +| text_formatting | sheetjs | font_size_14 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 14}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_size_24 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={} | +| text_formatting | sheetjs | font_size_24 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 24}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_size_36 | read | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={} | +| text_formatting | sheetjs | font_size_36 | write | data_mismatch | error | Expected values did not match actual values: expected={'font_size': 36}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_arial | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={} | +| text_formatting | sheetjs | font_arial | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Arial'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | font_times | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Times New Roman'}, actual={} | +| text_formatting | sheetjs | 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': 12.0} | +| text_formatting | sheetjs | font_courier | read | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={} | +| text_formatting | sheetjs | font_courier | write | data_mismatch | error | Expected values did not match actual values: expected={'font_name': 'Courier New'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | color_red | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={} | +| text_formatting | sheetjs | color_red | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#FF0000'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | color_blue | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={} | +| text_formatting | sheetjs | color_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#0000FF'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | color_green | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={} | +| text_formatting | sheetjs | color_green | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#00FF00'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | color_custom | read | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={} | +| text_formatting | sheetjs | color_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'font_color': '#8B4513'}, actual={'font_name': 'Calibri', 'font_size': 12.0} | +| text_formatting | sheetjs | combined | read | data_mismatch | error | Expected values did not match actual values: expected={'bold': True, 'font_size': 16, 'font_color': '#FF0000'}, actual={} | +| text_formatting | sheetjs | 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': 12.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_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_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_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_green | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_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_red | write | 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_blue | write | 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_green | write | 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_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_red | write | 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_blue | write | 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_green | write | 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_custom | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#8B4513'}, actual={} | +| background_colors | sheetjs | bg_red | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#FF0000'}, actual={} | +| background_colors | sheetjs | bg_blue | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#0000FF'}, actual={} | +| background_colors | sheetjs | bg_green | write | data_mismatch | error | Expected values did not match actual values: expected={'bg_color': '#00FF00'}, actual={} | +| background_colors | sheetjs | 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_currency | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_percent | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_date | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| 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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| 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_currency | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_percent | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_date | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_scientific | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| 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_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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| 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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00%'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '0.00E+00'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={} | +| 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'} | +| number_formats | libreoffice | numfmt_currency | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '$#,##0.00'}, actual={'number_format': '\\$#,##0.00'} | +| number_formats | libreoffice | numfmt_date | read | data_mismatch | error | Expected values did not match actual values: expected={'number_format': 'yyyy-mm-dd'}, actual={'number_format': 'YYYY-MM-DD'} | +| number_formats | libreoffice | numfmt_custom_text | write | data_mismatch | error | Expected values did not match actual values: expected={'number_format': '"USD" 0.00'}, actual={'number_format': '"USD "0.00'} | +| 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_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_format: pylightxl does not implement this feature | +| alignment | pylightxl | h_center | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_left | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_format: pyexcel exposes value-only cells | +| alignment | pyexcel | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| 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_left | write | 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_center | write | 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 | h_right | write | 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_top | write | 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_center | write | 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 | v_bottom | write | 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 | wrap_text | write | 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 | rotation_45 | write | 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 | 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_left | write | 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_center | write | 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 | h_right | write | 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_top | write | 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_center | write | 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 | v_bottom | write | 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 | wrap_text | write | 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 | rotation_45 | write | 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 | indent_2 | write | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | sheetjs | h_left | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | sheetjs | h_left | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'left'}, actual={} | +| alignment | sheetjs | h_center | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | sheetjs | h_center | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'center'}, actual={} | +| alignment | sheetjs | h_right | read | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | sheetjs | h_right | write | data_mismatch | error | Expected values did not match actual values: expected={'h_align': 'right'}, actual={} | +| alignment | sheetjs | v_top | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | sheetjs | v_top | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'top'}, actual={} | +| alignment | sheetjs | v_center | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | sheetjs | v_center | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'center'}, actual={} | +| alignment | sheetjs | v_bottom | read | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | sheetjs | v_bottom | write | data_mismatch | error | Expected values did not match actual values: expected={'v_align': 'bottom'}, actual={} | +| alignment | sheetjs | wrap_text | read | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | sheetjs | wrap_text | write | data_mismatch | error | Expected values did not match actual values: expected={'wrap': True}, actual={} | +| alignment | sheetjs | rotation_45 | read | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | sheetjs | rotation_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'rotation': 45}, actual={} | +| alignment | sheetjs | indent_2 | read | data_mismatch | error | Expected values did not match actual values: expected={'indent': 2}, actual={} | +| alignment | sheetjs | 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_up | write | 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_down | write | 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_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 | thin_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | medium_all | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dashed | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| borders | pylightxl | dashed | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support write_cell_border: pylightxl does not implement this feature | +| borders | pylightxl | dotted | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | thin_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | medium_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | thick_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | double | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dashed | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dashed | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | dotted | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', 'border_color': '#000000'}, actual={} | +| borders | pyexcel | dotted | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | dash_dot_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | top_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | bottom_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | left_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | right_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| borders | pyexcel | diagonal_up | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': 'thin'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', 'border_diagonal_down': 'thin'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, actual={} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, actual={} | +| 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 | 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_styles | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support write_cell_border: pyexcel exposes value-only cells | +| 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 | 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', '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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, 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 | 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_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 | 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 | 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'medium', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thick', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'double', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashed', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dotted', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDot', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'dashDotDot', '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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_down': '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_diagonal_up': 'thin', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#FF0000'}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#0000FF'}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'border_style': 'thin', 'border_color': '#8B4513'}, 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 | 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_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 | 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 | 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 | sheetjs | thin_all | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | thin_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | medium_all | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | medium_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | thick_all | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | thick_all | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | double | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | double | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | dashed | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | dashed | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | dotted | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | dotted | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | dash_dot | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | dash_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | dash_dot_dot | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | dash_dot_dot | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | top_only | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | top_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | bottom_only | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | bottom_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | left_only | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | left_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | right_only | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | right_only | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | diagonal_up | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | diagonal_up | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | diagonal_down | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | diagonal_down | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | diagonal_both | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | diagonal_both | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | color_red | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | color_red | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | color_blue | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | color_blue | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | color_custom | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | color_custom | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | mixed_styles | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | mixed_styles | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| borders | sheetjs | mixed_colors | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| borders | sheetjs | mixed_colors | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| 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_30 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_row_height: pylightxl does not implement this feature | +| 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 | 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| 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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': None} | +| 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| 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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| 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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 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 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': None} | +| 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} | +| dimensions | sheetjs | row_height_30 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 30}, actual={'row_height': None} | +| dimensions | sheetjs | row_height_45 | write | data_mismatch | error | Expected values did not match actual values: expected={'row_height': 45}, actual={'row_height': None} | +| dimensions | libreoffice | col_width_20 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 20}, actual={'column_width': 19.998} | +| dimensions | libreoffice | col_width_8 | read | data_mismatch | error | Expected values did not match actual values: expected={'column_width': 8}, actual={'column_width': 7.998} | +| 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_horizontal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support merge_cells: pylightxl does not implement this feature | +| 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_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 | 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_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 | 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_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_horizontal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support merge_cells: pyexcel does not expose this worksheet feature | +| 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | sheetjs | 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': 'Fill', 'top_left_bg_color': 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 | pylightxl | cf_cell_gt | 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_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 | 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_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 | 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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | 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_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 | 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_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 | sheetjs | cf_cell_gt | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_cell_gt | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | sheetjs | cf_formula_cross_sheet | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_formula_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | sheetjs | cf_text_contains | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_text_contains | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | sheetjs | cf_data_bar | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_data_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | sheetjs | cf_color_scale | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_color_scale | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | sheetjs | cf_stop_if_true | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips | +| conditional_formatting | sheetjs | cf_stop_if_true | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no | +| conditional_formatting | exceljs | 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': None, 'format': {'bg_color': '#FF0000'}}} | +| conditional_formatting | exceljs | 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={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': None, 'format': {'bg_color': '#FF0000'}}} | +| conditional_formatting | libreoffice | 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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'format': {'bg_color': '#000000'}}} | +| conditional_formatting | libreoffice | 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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'format': {'bg_color': '#000000'}}} | +| conditional_formatting | libreoffice | 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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH("foo",B2))', 'format': {'bg_color': '#000000'}}} | +| conditional_formatting | libreoffice | 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 | libreoffice | 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': None, 'format': {'bg_color': '#FF0000'}}} | +| conditional_formatting | libreoffice | 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={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': None, 'format': {'bg_color': '#000000'}}} | +| 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_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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_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 | 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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | 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_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 | sheetjs | dv_list_csv | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips | +| data_validation | sheetjs | dv_list_csv | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no | +| data_validation | sheetjs | dv_list_range | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips | +| data_validation | sheetjs | dv_list_range | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no | +| data_validation | sheetjs | dv_cross_sheet | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips | +| data_validation | sheetjs | dv_cross_sheet | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no | +| data_validation | sheetjs | dv_custom_formula | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips | +| data_validation | sheetjs | dv_custom_formula | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no | +| data_validation | sheetjs | dv_whole_between | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips | +| data_validation | sheetjs | dv_whole_between | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no | +| data_validation | libreoffice | dv_cross_sheet | write | data_mismatch | error | Expected values did not match actual values: expected={'validation': {'range': 'B4', 'validation_type': 'list', 'formula1': '=RegionList'}}, 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_external | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_hyperlink: pylightxl does not implement this feature | +| hyperlinks | pylightxl | link_internal | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_external | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| 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_internal | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| 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_mailto | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_hyperlink: pyexcel does not expose this worksheet feature | +| 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_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_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 | 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_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 | 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_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 | 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_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_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 | 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_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 | 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_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 | 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_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 | exceljs | 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': 'Example Docs', 'tooltip': None, 'internal': False}} | +| hyperlinks | exceljs | 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 | exceljs | 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={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1#Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', 'internal': False}} | +| hyperlinks | exceljs | 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': 'Email', 'tooltip': None, 'internal': False}} | +| hyperlinks | exceljs | 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': 'Search', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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': 'Example Docs', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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': 'Go Target', 'tooltip': None, 'internal': True}} | +| hyperlinks | libreoffice | 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={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': None, 'internal': True}} | +| hyperlinks | libreoffice | 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': 'Email', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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': 'Search', 'tooltip': None, 'internal': False}} | +| hyperlinks | libreoffice | 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={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': None, 'internal': False}} | +| 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_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 | 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 | 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_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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_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 | 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_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_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 | 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_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_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 | 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_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 | sheetjs | image_one_cell | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed | +| images | sheetjs | image_one_cell | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written) | +| images | sheetjs | image_two_cell_offset | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed | +| images | sheetjs | image_two_cell_offset | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written) | +| images | exceljs | image_one_cell | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors') | +| images | exceljs | 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 | exceljs | image_two_cell_offset | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors') | +| images | exceljs | 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_legacy | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature | +| 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_threaded | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support add_comment: pylightxl does not implement this feature | +| 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_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_legacy | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature | +| 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_threaded | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pyexcel does not support add_comment: pyexcel does not expose this worksheet feature | +| 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_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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', '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_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 | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B3', 'text': 'Threaded fallback', '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 | read | data_mismatch | error | Expected values did not match actual values: expected={'comment': {'cell': 'B4', 'text': 'Another note', '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_b2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: pylightxl does not support set_freeze_panes: pylightxl does not implement this feature | +| freeze_panes | pylightxl | freeze_d5 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_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 | 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 | 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 | 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 | 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_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 | 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 | 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 | 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 | 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_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 | 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 | 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 | 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 | 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 | sheetjs | freeze_b2 | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed | +| freeze_panes | sheetjs | freeze_b2 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set | +| freeze_panes | sheetjs | freeze_d5 | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed | +| freeze_panes | sheetjs | freeze_d5 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set | +| freeze_panes | sheetjs | split_2x1 | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed | +| freeze_panes | sheetjs | split_2x1 | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set | +| freeze_panes | libreoffice | 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 | 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': 'not_found', 'refers_to': ''} | +| 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_simple_cell | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_cell_range | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_formula_ref | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_sheet_scope | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_cross_sheet | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| named_ranges | pylightxl | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement named range writes | +| named_ranges | pylightxl | nr_special_chars | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_simple_cell | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| named_ranges | pyexcel | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range writes | +| named_ranges | pyexcel | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement named range reads | +| 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_simple_cell | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| named_ranges | pandas | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: pandas does not implement named range writes | +| named_ranges | pandas | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: pandas does not implement named range reads | +| 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_simple_cell | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_cell_range | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_cell_range | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_formula_ref | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_formula_ref | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_sheet_scope | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_sheet_scope | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_cross_sheet | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_cross_sheet | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | tablib | nr_special_chars | read | unsupported_feature | warning | NotImplementedError: tablib does not implement named range reads | +| named_ranges | tablib | nr_special_chars | write | unsupported_feature | warning | NotImplementedError: tablib does not implement named range writes | +| named_ranges | exceljs | 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': 'not_found', 'refers_to': ''} | +| named_ranges | exceljs | 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': ''} | +| 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_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 | 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_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 | wolfxl | tbl_autofilter | read | data_mismatch | error | Expected values did not match actual values: 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': False}} | +| tables | pylightxl | tbl_basic | 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_no_style | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_single_col | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_single_row | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| tables | pylightxl | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement table writes | +| tables | pylightxl | tbl_autofilter | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| tables | pyexcel | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table writes | +| tables | pyexcel | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement table reads | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| tables | pandas | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: pandas does not implement table writes | +| tables | pandas | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: pandas does not implement table reads | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_with_totals | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_with_totals | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_no_style | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_no_style | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_single_col | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_single_col | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_single_row | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_single_row | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | tablib | tbl_autofilter | read | unsupported_feature | warning | NotImplementedError: tablib does not implement table reads | +| tables | tablib | tbl_autofilter | write | unsupported_feature | warning | NotImplementedError: tablib does not implement table writes | +| tables | sheetjs | tbl_basic | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_basic | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | sheetjs | tbl_with_totals | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_with_totals | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | sheetjs | tbl_no_style | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_no_style | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | sheetjs | tbl_single_col | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_single_col | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | sheetjs | tbl_single_row | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_single_row | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | sheetjs | tbl_autofilter | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed | +| tables | sheetjs | tbl_autofilter | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable | +| tables | exceljs | tbl_basic | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | exceljs | tbl_with_totals | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | exceljs | tbl_no_style | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | exceljs | tbl_single_col | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | exceljs | tbl_single_row | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | exceljs | tbl_autofilter | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name') | +| tables | libreoffice | tbl_single_row | write | data_mismatch | error | Expected values did not match actual values: expected={'table': {'name': 'EmptyTable', 'ref': 'E23:G23', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium9', 'columns': ['A', 'B', 'C']}}, actual={'table': {'name': 'EmptyTable', 'ref': 'not_found', 'header_row': True, 'totals_row': False, 'style': None, 'columns': []}} | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement sheet protection writes | +| sheet_protection | pylightxl | prot_password | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| sheet_protection | pylightxl | prot_password | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement sheet protection writes | +| sheet_protection | pylightxl | prot_granular | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection writes | +| sheet_protection | pyexcel | prot_password | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection reads | +| sheet_protection | pyexcel | prot_password | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection writes | +| sheet_protection | pyexcel | prot_granular | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement sheet protection reads | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection writes | +| sheet_protection | pandas | prot_password | read | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection reads | +| sheet_protection | pandas | prot_password | write | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection writes | +| sheet_protection | pandas | prot_granular | read | unsupported_feature | warning | NotImplementedError: pandas does not implement sheet protection reads | +| 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_basic | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| sheet_protection | tablib | prot_password | read | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection reads | +| sheet_protection | tablib | prot_password | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| sheet_protection | tablib | prot_granular | read | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection reads | +| sheet_protection | tablib | prot_granular | write | unsupported_feature | warning | NotImplementedError: tablib does not implement sheet protection writes | +| sheet_protection | sheetjs | prot_basic | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs | +| sheet_protection | sheetjs | prot_password | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs | +| sheet_protection | sheetjs | prot_granular | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs | +| sheet_protection | exceljs | prot_password | read | data_mismatch | error | Expected values did not match actual values: 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': False, 'format_cells': True, 'insert_rows': True, 'select_locked_cells': False, 'select_unlocked_cells': False, 'sort': True, 'auto_filter': True}} | +| sheet_protection | libreoffice | prot_basic | read | data_mismatch | error | Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': False, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': None}} | +| sheet_protection | libreoffice | prot_password | read | data_mismatch | error | Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': True, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': None}} | +| sheet_protection | libreoffice | prot_granular | read | data_mismatch | error | Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': False, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': None}} | +| sheet_protection | libreoffice | prot_granular | write | data_mismatch | error | Expected values did not match actual values: 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': True, 'insert_rows': True, 'select_locked_cells': False, 'select_unlocked_cells': False, 'sort': True, 'auto_filter': True}} | +| 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_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 | 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_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_landscape | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement page setup writes | +| page_setup | pylightxl | page_setup_scale | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| page_setup | pylightxl | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pylightxl does not implement page setup writes | +| page_setup | pylightxl | page_setup_titles | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_landscape | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup writes | +| page_setup | pyexcel | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup reads | +| page_setup | pyexcel | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup writes | +| page_setup | pyexcel | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement page setup reads | +| 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_landscape | write | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup writes | +| page_setup | pandas | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup reads | +| page_setup | pandas | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup writes | +| page_setup | pandas | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: pandas does not implement page setup reads | +| 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_landscape | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| page_setup | tablib | page_setup_scale | read | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup reads | +| page_setup | tablib | page_setup_scale | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| page_setup | tablib | page_setup_titles | read | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup reads | +| page_setup | tablib | page_setup_titles | write | unsupported_feature | warning | NotImplementedError: tablib does not implement page setup writes | +| page_setup | sheetjs | 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': {}} | +| page_setup | sheetjs | page_setup_landscape | write | 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': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | sheetjs | page_setup_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {}} | +| page_setup | sheetjs | page_setup_scale | write | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | sheetjs | 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': {'print_title_rows': '$1:$2'}} | +| page_setup | sheetjs | 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': '$1:$2', 'header_center': None, 'footer_center': None}} | +| page_setup | exceljs | 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': 1, 'scale': 100, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | exceljs | page_setup_landscape | write | 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': 1, 'scale': 100, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | exceljs | page_setup_scale | read | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | exceljs | page_setup_scale | write | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | exceljs | 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': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 100, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}} | +| page_setup | libreoffice | 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': {'fit_to_height': None, 'fit_to_width': None, 'footer_center': None, 'header_center': None, 'orientation': 'landscape', 'print_title_rows': None, 'scale': 100}} | +| page_setup | libreoffice | page_setup_landscape | write | 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': 0, 'scale': 100, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | libreoffice | page_setup_scale | write | data_mismatch | error | Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}} | +| page_setup | libreoffice | 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': {'fit_to_height': None, 'fit_to_width': None, 'footer_center': 'Page &P', 'header_center': 'ExcelBench Report', 'orientation': 'portrait', 'print_title_rows': '$1:$2', 'scale': 100}} | +| page_setup | libreoffice | 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': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 100, 'print_title_rows': '$1:$2', 'header_center': 'ExcelBench Report', 'footer_center': 'Page &P'}} | +| 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 | wolfxl | chart_bar | write | invalid_input | error | TypeError: argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str' | +| chart_anchor | wolfxl | chart_line | write | invalid_input | error | TypeError: argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str' | +| chart_anchor | pylightxl | chart_bar | 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 | read | invalid_input | error | TypeError: expected string or bytes-like object, got 'NoneType' | +| 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_bar | write | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor writes | +| chart_anchor | pyexcel | chart_line | read | unsupported_feature | warning | NotImplementedError: pyexcel does not implement chart anchor reads | +| 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_bar | write | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor writes | +| chart_anchor | pandas | chart_line | read | unsupported_feature | warning | NotImplementedError: pandas does not implement chart anchor reads | +| 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_bar | write | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor writes | +| chart_anchor | tablib | chart_line | read | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor reads | +| chart_anchor | tablib | chart_line | write | unsupported_feature | warning | NotImplementedError: tablib does not implement chart anchor writes | +| chart_anchor | sheetjs | chart_bar | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets | +| chart_anchor | sheetjs | chart_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support chart: SheetJS CE cannot create charts | +| chart_anchor | sheetjs | chart_line | read | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets | +| chart_anchor | sheetjs | chart_line | write | unsupported_feature | warning | UnsupportedAdapterOperationError: sheetjs does not support chart: SheetJS CE cannot create charts | +| chart_anchor | exceljs | chart_bar | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors') | +| chart_anchor | exceljs | chart_bar | write | unsupported_feature | warning | UnsupportedAdapterOperationError: exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API | +| chart_anchor | exceljs | chart_line | read | internal | error | HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors') | +| chart_anchor | exceljs | chart_line | write | unsupported_feature | warning | UnsupportedAdapterOperationError: exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API | +| chart_anchor | libreoffice | chart_bar | read | data_mismatch | error | Expected values did not match actual values: expected={'charts': [{'type': 'bar', 'anchor_type': 'twoCell', 'from': 'B2', 'to': 'H12', 'data_ref': 'E2:E8', 'categories_ref': 'F2:F8'}]}, actual={'charts': [{'anchor_type': 'twoCell', 'from': 'B2', 'to': 'G11', 'type': 'bar'}, {'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11', 'type': 'line'}]} | +| chart_anchor | libreoffice | chart_bar | write | data_mismatch | error | Expected values did not match actual values: 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': 'G11'}, {'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11'}]} | +| chart_anchor | libreoffice | chart_line | read | data_mismatch | error | Expected values did not match actual values: expected={'charts': [{'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'P12', 'data_ref': 'E2:E8', 'categories_ref': 'F2:F8'}]}, actual={'charts': [{'anchor_type': 'twoCell', 'from': 'B2', 'to': 'G11', 'type': 'bar'}, {'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11', 'type': 'line'}]} | +| chart_anchor | libreoffice | chart_line | write | data_mismatch | error | Expected values did not match actual values: 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': 'G11'}, {'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11'}]} | + +## 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 | ✅ | ✅ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — 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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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 | ✅ | ✅ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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 | ✅ | ✅ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — 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 | ✅ | + +**sheetjs** — Read: 🟢 3 | Write: 🟢 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 + + +### chart_anchor + +**aspose-cells-foss** — Read: 🟢 3 | Write: 🟢 3 + +**exceljs** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**libreoffice** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ❌ | ❌ | +| Chart: line with twoCell anchor | edge | ❌ | ❌ | + +**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 | ❌ | + +**sheetjs** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Chart: bar with twoCell anchor | basic | ✅ | ❌ | +| Chart: line with twoCell anchor | edge | ✅ | ❌ | + +**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 | ✅ | ❌ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟢 3 + +**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 + +**exceljs** — Read: 🟡 2 | Write: 🟡 2 + +| 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 | ❌ | ❌ | + +**libreoffice** — Read: 🟡 2 | 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 | ❌ | ❌ | + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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: 🟢 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 | +|------|-----------|-------| +| 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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟡 2 + +| 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 | ✅ | ✅ | + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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 | ❌ | ✅ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — 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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟠 1 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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 + +**exceljs** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ✅ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ✅ | ✅ | +| Formula - cross sheet | basic | ✅ | ✅ | + +**libreoffice** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Formula - SUM | basic | ✅ | ✅ | +| Formula - cell reference | basic | ❌ | ✅ | +| Formula - concat | basic | ✅ | ✅ | +| Formula - cross sheet | basic | ✅ | ✅ | + +**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 | ❌ | + +**sheetjs** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟡 2 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Freeze panes at B2 | basic | ✅ | ✅ | +| Freeze panes at D5 | edge | ✅ | ✅ | +| Split panes row=2 col=1 | edge | ✅ | ❌ | + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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 | ❌ | ✅ | + +**exceljs** — Read: 🔴 0 | Write: 🟡 2 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Hyperlink: external URL | basic | ❌ | ✅ | +| Hyperlink: internal sheet | edge | ❌ | ❌ | +| Hyperlink: mailto | basic | ❌ | ✅ | +| Hyperlink: long encoded URL | edge | ❌ | ✅ | + +**libreoffice** — Read: 🔴 0 | Write: 🔴 0 + +| 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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | ❌ | + +**exceljs** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Image: one-cell anchor | basic | ❌ | ❌ | +| Image: two-cell anchor with offset | edge | ❌ | ❌ | + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — Read: 🔴 0 | Write: 🔴 0 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — 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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟡 2 + +| 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 | ✅ | ❌ | + +**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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — 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 + +**sheetjs** — Read: 🟢 3 | Write: 🟢 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 | ✅ | ✅ | + +**exceljs** — Read: 🟡 2 | 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 | ✅ | ✅ | + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟢 3 + +**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: 🟡 2 | 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 + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟠 1 | Write: 🟠 1 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Format - currency | basic | ✅ | ❌ | +| Format - percent | basic | ✅ | ✅ | +| Format - date | basic | ❌ | ✅ | +| Format - scientific | basic | ✅ | ✅ | +| Format - custom text | basic | ✅ | ❌ | + +**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 | ❌ | + +**sheetjs** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | ❌ | + +**exceljs** — 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 | ✅ | ❌ | + +**libreoffice** — 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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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). + +**exceljs** +- Notes: Unsupported on macOS without a Windows-generated pivot fixture (fixtures/excel/tier2/15_pivot_tables.xlsx). + +**libreoffice** +- 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). + +**sheetjs** +- 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 + +**exceljs** — Read: 🟠 1 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ✅ | ✅ | +| Protection: with password hash | basic | ❌ | ✅ | +| Protection: granular attribute flags | edge | ✅ | ✅ | + +**libreoffice** — Read: 🔴 0 | Write: 🟡 2 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| Protection: basic (OOXML defaults) | basic | ❌ | ✅ | +| Protection: with password hash | basic | ❌ | ✅ | +| Protection: granular attribute flags | edge | ❌ | ❌ | + +**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 | ❌ | + +**sheetjs** — Read: 🔴 0 | Write: 🟢 3 + +| Test | Importance | Read | Write | +|------|-----------|------|-------| +| 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 | ✅ | ✅ | + +**exceljs** — Read: 🔴 0 | Write: 🟢 3 + +| 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 | ❌ | ✅ | + +**libreoffice** — Read: 🟢 3 | Write: 🟡 2 + +| 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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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: 🟡 2 | Write: 🟢 3 + +| 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 | ❌ | ✅ | + +**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 | ✅ | ❌ | + +**exceljs** — Read: 🟢 3 | Write: 🟢 3 + +**libreoffice** — Read: 🟢 3 | Write: 🟢 3 + +**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 | ❌ | + +**sheetjs** — 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 | ❌ | ❌ | + +**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-10-02/xlsx/WHY_FAILED.md b/results-2026-10-02/xlsx/WHY_FAILED.md new file mode 100644 index 0000000..b6560af --- /dev/null +++ b/results-2026-10-02/xlsx/WHY_FAILED.md @@ -0,0 +1,9859 @@ +# 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. + +## cell_values / libreoffice / read / boolean_true + +- What failed: benchmark expectation 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 / libreoffice / read / boolean_false + +- What failed: benchmark expectation 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 + +## formulas / sheetjs / 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 / exceljs / 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 / libreoffice / 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 + +## 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 + +## text_formatting / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 + +## background_colors / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 + +## number_formats / libreoffice / 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 / libreoffice / 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 / libreoffice / 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. + +## alignment / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 / sheetjs / 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 + +## borders / sheetjs / read / thin_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / medium_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / thick_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / double + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / dashed + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / dotted + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / dash_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / dash_dot_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / top_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / bottom_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / left_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / right_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / diagonal_up + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / diagonal_down + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / diagonal_both + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / mixed_styles + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / read / mixed_colors + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / thin_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / medium_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / thick_all + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / double + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / dashed + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / dotted + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / dash_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / dash_dot_dot + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / top_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / bottom_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / left_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / right_only + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / diagonal_up + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / diagonal_down + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / diagonal_both + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / color_red + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / color_blue + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / color_custom + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / mixed_styles + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## borders / sheetjs / write / mixed_colors + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles +- Next debug surface: treat as unsupported capability, not a semantic regression + +## 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. + +## dimensions / sheetjs / 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 / sheetjs / 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 / libreoffice / 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 / libreoffice / 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. + +## 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 + +## merged_cells / sheetjs / 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 / 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 + +## conditional_formatting / sheetjs / read / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / read / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / read / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / read / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / read / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / read / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_cell_gt + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_formula_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_text_contains + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_data_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_color_scale + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / sheetjs / write / cf_stop_if_true + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no conditional formatting API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## conditional_formatting / exceljs / 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 / exceljs / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 + +## data_validation / sheetjs / read / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / read / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / read / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / read / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / read / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX reader skips +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / write / dv_list_csv + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / write / dv_list_range + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / write / dv_cross_sheet + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / write / dv_custom_formula + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / sheetjs / write / dv_whole_between + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE has no data validation API; the XLSX writer emits no +- Next debug surface: treat as unsupported capability, not a semantic regression + +## data_validation / libreoffice / 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 + +## 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 + +## hyperlinks / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / 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 + +## images / sheetjs / read / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / sheetjs / read / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / sheetjs / write / image_one_cell + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot embed images (drawing parts are not written) +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / sheetjs / write / image_two_cell_offset + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot embed images (drawing parts are not written) +- Next debug surface: treat as unsupported capability, not a semantic regression + +## images / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 + +## freeze_panes / sheetjs / read / freeze_b2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE parses only for zoom and right-to-left; panes are not exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / sheetjs / read / freeze_d5 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE parses only for zoom and right-to-left; panes are not exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / sheetjs / read / split_2x1 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE parses only for zoom and right-to-left; panes are not exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / sheetjs / write / freeze_b2 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX writer emits without a element, so panes cannot be set +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / sheetjs / write / freeze_d5 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX writer emits without a element, so panes cannot be set +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / sheetjs / write / split_2x1 + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX writer emits without a element, so panes cannot be set +- Next debug surface: treat as unsupported capability, not a semantic regression + +## freeze_panes / libreoffice / 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 / 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 + +## named_ranges / exceljs / 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 / exceljs / 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 + +## 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 / wolfxl / 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 / 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 + +## tables / sheetjs / read / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / read / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / read / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / read / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / read / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / read / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_with_totals + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_no_style + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_single_col + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_single_row + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / sheetjs / write / tbl_autofilter + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable +- Next debug surface: treat as unsupported capability, not a semantic regression + +## tables / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 / exceljs / 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 / libreoffice / write / 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 + +## 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 + +## sheet_protection / sheetjs / read / prot_basic + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / sheetjs / read / prot_password + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / sheetjs / read / prot_granular + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs +- Next debug surface: treat as unsupported capability, not a semantic regression + +## sheet_protection / exceljs / read / prot_password + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## sheet_protection / libreoffice / read / prot_basic + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## sheet_protection / libreoffice / read / prot_password + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## sheet_protection / libreoffice / read / prot_granular + +- What failed: benchmark expectation did not match actual output. +- Likely cause: no known failure archetype matched this payload. +- Next debug surface: inspect expected/actual payloads in results.json. + +## sheet_protection / libreoffice / write / prot_granular + +- What failed: benchmark expectation 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 / 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 + +## page_setup / sheetjs / 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 / sheetjs / read / page_setup_scale + +- What failed: benchmark expectation 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 / sheetjs / 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 / sheetjs / write / 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 / sheetjs / write / page_setup_scale + +- What failed: benchmark expectation 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 / sheetjs / 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 / exceljs / 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 / exceljs / read / page_setup_scale + +- What failed: benchmark expectation 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 / exceljs / write / 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 / exceljs / write / page_setup_scale + +- What failed: benchmark expectation 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 / exceljs / 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 / libreoffice / 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 / libreoffice / 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 / libreoffice / write / 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 / libreoffice / write / page_setup_scale + +- What failed: benchmark expectation 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 / libreoffice / 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. + +## 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 / wolfxl / write / 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 / wolfxl / write / 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 / 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 + +## chart_anchor / sheetjs / read / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse charts or drawing anchors in worksheets +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / sheetjs / read / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE does not parse charts or drawing anchors in worksheets +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / sheetjs / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create charts +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / sheetjs / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: SheetJS CE cannot create charts +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / exceljs / 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 / exceljs / 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 / exceljs / write / chart_bar + +- What failed: adapter reported this operation as unsupported +- Likely cause: ExcelJS 4.4.0 has no chart creation API +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / exceljs / write / chart_line + +- What failed: adapter reported this operation as unsupported +- Likely cause: ExcelJS 4.4.0 has no chart creation API +- Next debug surface: treat as unsupported capability, not a semantic regression + +## chart_anchor / libreoffice / 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 / libreoffice / 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 / libreoffice / write / 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 / libreoffice / write / 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 diff --git a/results-2026-10-02/xlsx/heatmap.png b/results-2026-10-02/xlsx/heatmap.png new file mode 100644 index 0000000..3a14790 Binary files /dev/null and b/results-2026-10-02/xlsx/heatmap.png differ diff --git a/results-2026-10-02/xlsx/heatmap.svg b/results-2026-10-02/xlsx/heatmap.svg new file mode 100644 index 0000000..6d63c14 --- /dev/null +++ b/results-2026-10-02/xlsx/heatmap.svg @@ -0,0 +1,4660 @@ + + + + + + + + 2026-10-01T23:59:00.083495 + image/svg+xml + + + Matplotlib v3.10.8, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/results-2026-10-02/xlsx/history.jsonl b/results-2026-10-02/xlsx/history.jsonl new file mode 100644 index 0000000..8e5b9ef --- /dev/null +++ b/results-2026-10-02/xlsx/history.jsonl @@ -0,0 +1 @@ +{"run_date": "2026-10-02T06:55:36.881036+00:00", "commit": "b65866c", "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": 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": 2, "write": 2}, "tables": {"read": 2, "write": 3}, "sheet_protection": {"read": 3, "write": 3}, "page_setup": {"read": 3, "write": 2}, "chart_anchor": {"read": 3, "write": 0}}, "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}}, "sheetjs": {"cell_values": {"read": 3, "write": 3}, "formulas": {"read": 1, "write": 3}, "text_formatting": {"read": 0, "write": 0}, "background_colors": {"read": 3, "write": 0}, "number_formats": {"read": 3, "write": 3}, "alignment": {"read": 0, "write": 0}, "borders": {"read": 0, "write": 0}, "dimensions": {"read": 3, "write": 1}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 3, "write": 2}, "conditional_formatting": {"read": 0, "write": 0}, "data_validation": {"read": 0, "write": 0}, "hyperlinks": {"read": 3, "write": 3}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 3}, "freeze_panes": {"read": 0, "write": 0}, "named_ranges": {"read": 3, "write": 3}, "tables": {"read": 0, "write": 0}, "sheet_protection": {"read": 0, "write": 3}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}, "exceljs": {"cell_values": {"read": 3, "write": 3}, "formulas": {"read": 1, "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": 2, "write": 2}, "data_validation": {"read": 3, "write": 3}, "hyperlinks": {"read": 0, "write": 2}, "images": {"read": 0, "write": 0}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 3}, "freeze_panes": {"read": 3, "write": 3}, "named_ranges": {"read": 2, "write": 2}, "tables": {"read": 0, "write": 3}, "sheet_protection": {"read": 1, "write": 3}, "page_setup": {"read": 0, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}, "libreoffice": {"cell_values": {"read": 1, "write": 3}, "formulas": {"read": 1, "write": 3}, "text_formatting": {"read": 3, "write": 3}, "background_colors": {"read": 3, "write": 3}, "number_formats": {"read": 1, "write": 1}, "alignment": {"read": 3, "write": 3}, "borders": {"read": 3, "write": 3}, "dimensions": {"read": 1, "write": 3}, "multiple_sheets": {"read": 3, "write": 3}, "merged_cells": {"read": 3, "write": 3}, "conditional_formatting": {"read": 2, "write": 0}, "data_validation": {"read": 3, "write": 2}, "hyperlinks": {"read": 0, "write": 0}, "images": {"read": 3, "write": 3}, "pivot_tables": {"read": null, "write": null}, "comments": {"read": 3, "write": 3}, "freeze_panes": {"read": 3, "write": 2}, "named_ranges": {"read": 3, "write": 3}, "tables": {"read": 3, "write": 2}, "sheet_protection": {"read": 0, "write": 2}, "page_setup": {"read": 1, "write": 0}, "chart_anchor": {"read": 0, "write": 0}}}} diff --git a/results-2026-10-02/xlsx/matrix.csv b/results-2026-10-02/xlsx/matrix.csv new file mode 100644 index 0000000..2d17204 --- /dev/null +++ b/results-2026-10-02/xlsx/matrix.csv @@ -0,0 +1,375 @@ +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 +sheetjs,cell_values,3,3 +exceljs,cell_values,3,3 +libreoffice,cell_values,1,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 +sheetjs,formulas,1,3 +exceljs,formulas,1,3 +libreoffice,formulas,1,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 +sheetjs,text_formatting,0,0 +exceljs,text_formatting,3,3 +libreoffice,text_formatting,3,3 +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 +sheetjs,background_colors,3,0 +exceljs,background_colors,3,3 +libreoffice,background_colors,3,3 +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 +sheetjs,number_formats,3,3 +exceljs,number_formats,3,3 +libreoffice,number_formats,1,1 +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 +sheetjs,alignment,0,0 +exceljs,alignment,3,3 +libreoffice,alignment,3,3 +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 +sheetjs,borders,0,0 +exceljs,borders,3,3 +libreoffice,borders,3,3 +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 +sheetjs,dimensions,3,1 +exceljs,dimensions,3,3 +libreoffice,dimensions,1,3 +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 +sheetjs,multiple_sheets,3,3 +exceljs,multiple_sheets,3,3 +libreoffice,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 +sheetjs,merged_cells,3,2 +exceljs,merged_cells,3,3 +libreoffice,merged_cells,3,3 +openpyxl,conditional_formatting,3,3 +xlsxwriter,conditional_formatting,,3 +python-calamine,conditional_formatting,0, +aspose-cells-foss,conditional_formatting,3,3 +wolfxl,conditional_formatting,3,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 +sheetjs,conditional_formatting,0,0 +exceljs,conditional_formatting,2,2 +libreoffice,conditional_formatting,2,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 +sheetjs,data_validation,0,0 +exceljs,data_validation,3,3 +libreoffice,data_validation,3,2 +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 +sheetjs,hyperlinks,3,3 +exceljs,hyperlinks,0,2 +libreoffice,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 +sheetjs,images,0,0 +exceljs,images,0,0 +libreoffice,images,3,3 +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,, +sheetjs,pivot_tables,, +exceljs,pivot_tables,, +libreoffice,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 +sheetjs,comments,3,3 +exceljs,comments,3,3 +libreoffice,comments,3,3 +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 +sheetjs,freeze_panes,0,0 +exceljs,freeze_panes,3,3 +libreoffice,freeze_panes,3,2 +openpyxl,named_ranges,3,3 +xlsxwriter,named_ranges,,0 +python-calamine,named_ranges,0, +aspose-cells-foss,named_ranges,2,3 +wolfxl,named_ranges,2,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 +sheetjs,named_ranges,3,3 +exceljs,named_ranges,2,2 +libreoffice,named_ranges,3,3 +openpyxl,tables,3,3 +xlsxwriter,tables,,0 +python-calamine,tables,0, +aspose-cells-foss,tables,1,1 +wolfxl,tables,2,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 +sheetjs,tables,0,0 +exceljs,tables,0,3 +libreoffice,tables,3,2 +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 +sheetjs,sheet_protection,0,3 +exceljs,sheet_protection,1,3 +libreoffice,sheet_protection,0,2 +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 +sheetjs,page_setup,0,0 +exceljs,page_setup,0,0 +libreoffice,page_setup,1,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,0 +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 +sheetjs,chart_anchor,0,0 +exceljs,chart_anchor,0,0 +libreoffice,chart_anchor,0,0 \ No newline at end of file diff --git a/results-2026-10-02/xlsx/results.json b/results-2026-10-02/xlsx/results.json new file mode 100644 index 0000000..a5a3a7b --- /dev/null +++ b/results-2026-10-02/xlsx/results.json @@ -0,0 +1,101319 @@ +{ + "metadata": { + "benchmark_version": "0.1.0", + "run_date": "2026-10-02T06:55:36.881036+00:00", + "excel_version": "16.105.3", + "platform": "Darwin-arm64", + "profile": "xlsx" + }, + "libraries": { + "openpyxl": { + "name": "openpyxl", + "version": "3.1.5", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "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": [ + "read", + "write" + ] + }, + "wolfxl": { + "name": "wolfxl", + "version": "2.0.5", + "language": "python", + "capabilities": [ + "read", + "modify", + "write" + ] + }, + "pylightxl": { + "name": "pylightxl", + "version": "1.61", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "xlrd": { + "name": "xlrd", + "version": "2.0.2", + "language": "python", + "capabilities": [ + "read" + ] + }, + "pyexcel": { + "name": "pyexcel", + "version": "0.7.4", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "xlwt": { + "name": "xlwt", + "version": "1.3.0", + "language": "python", + "capabilities": [ + "write" + ] + }, + "pandas": { + "name": "pandas", + "version": "3.0.0", + "language": "python", + "capabilities": [ + "read", + "write" + ] + }, + "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": [ + "read", + "write" + ] + }, + "sheetjs": { + "name": "sheetjs", + "version": "0.20.3", + "language": "javascript", + "capabilities": [ + "read", + "modify", + "write" + ] + }, + "exceljs": { + "name": "exceljs", + "version": "4.4.0", + "language": "javascript", + "capabilities": [ + "read", + "modify", + "write" + ] + }, + "libreoffice": { + "name": "libreoffice", + "version": "26.8.0.3 (build bce0998afefdbc355585ca324285661a2170ba77)", + "language": "cli", + "capabilities": [ + "read", + "modify", + "write" + ] + } + }, + "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": "cell_values", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "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": false, + "expected": { + "type": "boolean", + "value": true + }, + "actual": { + "type": "formula", + "value": "=TRUE()" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "boolean_true", + "sheet": "cell_values", + "cell": "B14" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'boolean', 'value': True}, actual={'type': 'formula', 'value': '=TRUE()'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "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": false, + "expected": { + "type": "boolean", + "value": false + }, + "actual": { + "type": "formula", + "value": "=FALSE()" + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "cell_values", + "operation": "read", + "test_case_id": "boolean_false", + "sheet": "cell_values", + "cell": "B15" + }, + "adapter_message": "Expected values did not match actual values: expected={'type': 'boolean', 'value': False}, actual={'type': 'formula', 'value': '=FALSE()'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "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": "formulas", + "library": "sheetjs", + "scores": { + "read": 1, + "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": 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": 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": "exceljs", + "scores": { + "read": 1, + "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": 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": 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": "libreoffice", + "scores": { + "read": 1, + "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": 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": 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": "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": "text_formatting", + "library": "sheetjs", + "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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": 12.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': 12.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": "exceljs", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bold": { + "read": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 12 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "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, + "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, + "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, + "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, + "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": "libreoffice", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "bold": { + "read": { + "passed": true, + "expected": { + "bold": true + }, + "actual": { + "bold": true, + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "italic": true + }, + "actual": { + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "underline": "single" + }, + "actual": { + "underline": "single", + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "underline": "double" + }, + "actual": { + "underline": "double", + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "strikethrough": true + }, + "actual": { + "strikethrough": true, + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "bold": true, + "italic": true + }, + "actual": { + "bold": true, + "italic": true, + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_size": 8 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 8, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_size": 14 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 14, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_size": 24 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 24, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_size": 36 + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 36, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_name": "Arial" + }, + "actual": { + "font_name": "Arial", + "font_size": 12, + "font_color": "#000000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "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": { + "read": { + "passed": true, + "expected": { + "font_name": "Times New Roman" + }, + "actual": { + "font_name": "Times New Roman", + "font_size": 12, + "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", + "font_size": 10.0 + }, + "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, + "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", + "font_size": 10.0 + }, + "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, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font 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": { + "read": { + "passed": true, + "expected": { + "font_color": "#0000FF" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font 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": { + "read": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Aptos Narrow", + "font_size": 12, + "font_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - green" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#00FF00" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "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, + "font_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Font color - custom (#8B4513)" + }, + "write": { + "passed": true, + "expected": { + "font_color": "#8B4513" + }, + "actual": { + "font_name": "Arial", + "font_size": 10.0, + "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, + "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_name": "Arial", + "font_size": 16.0, + "font_color": "#FF0000" + }, + "notes": null, + "diagnostics": [], + "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": "background_colors", + "library": "sheetjs", + "scores": { + "read": 3, + "write": 0 + }, + "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": 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": true, + "expected": { + "bg_color": "#0000FF" + }, + "actual": { + "bg_color": "#0000FF" + }, + "notes": null, + "diagnostics": [], + "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": true, + "expected": { + "bg_color": "#00FF00" + }, + "actual": { + "bg_color": "#00FF00" + }, + "notes": null, + "diagnostics": [], + "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": true, + "expected": { + "bg_color": "#8B4513" + }, + "actual": { + "bg_color": "#8B4513" + }, + "notes": null, + "diagnostics": [], + "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": "exceljs", + "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": "libreoffice", + "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": "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": "number_formats", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "scores": { + "read": 1, + "write": 1 + }, + "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": false, + "expected": { + "number_format": "$#,##0.00" + }, + "actual": { + "number_format": "\\$#,##0.00" + }, + "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': '\\\\$#,##0.00'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_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": 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": false, + "expected": { + "number_format": "yyyy-mm-dd" + }, + "actual": { + "number_format": "YYYY-MM-DD" + }, + "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={'number_format': 'YYYY-MM-DD'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_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": 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": false, + "expected": { + "number_format": "\"USD\" 0.00" + }, + "actual": { + "number_format": "\"USD \"0.00" + }, + "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': '\"USD \"0.00'}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata changed", + "probable_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": "alignment", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "scores": { + "read": 3, + "write": 3 + }, + "test_cases": { + "h_left": { + "read": { + "passed": true, + "expected": { + "h_align": "left" + }, + "actual": { + "h_align": "left", + "v_align": "bottom", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - 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": { + "read": { + "passed": true, + "expected": { + "h_align": "center" + }, + "actual": { + "h_align": "center", + "v_align": "bottom", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - 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": { + "read": { + "passed": true, + "expected": { + "h_align": "right" + }, + "actual": { + "h_align": "right", + "v_align": "bottom", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - 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": { + "read": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "v_align": "top", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + }, + "write": { + "passed": true, + "expected": { + "v_align": "top" + }, + "actual": { + "h_align": "general", + "v_align": "top" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - top" + } + }, + "v_center": { + "read": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "v_align": "center", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + }, + "write": { + "passed": true, + "expected": { + "v_align": "center" + }, + "actual": { + "h_align": "general", + "v_align": "center" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - center" + } + }, + "v_bottom": { + "read": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "v_align": "bottom", + "wrap": false + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + }, + "write": { + "passed": true, + "expected": { + "v_align": "bottom" + }, + "actual": { + "h_align": "general", + "v_align": "bottom" + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - bottom" + } + }, + "wrap_text": { + "read": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "v_align": "bottom", + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + }, + "write": { + "passed": true, + "expected": { + "wrap": true + }, + "actual": { + "h_align": "general", + "v_align": "bottom", + "wrap": true + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - wrap text" + } + }, + "rotation_45": { + "read": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "h_align": "left", + "v_align": "bottom", + "wrap": false, + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + }, + "write": { + "passed": true, + "expected": { + "rotation": 45 + }, + "actual": { + "h_align": "general", + "v_align": "bottom", + "rotation": 45 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - rotation 45" + } + }, + "indent_2": { + "read": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "v_align": "bottom", + "wrap": false, + "indent": 2 + }, + "notes": null, + "diagnostics": [], + "importance": "basic", + "label": "Align - indent 2" + }, + "write": { + "passed": true, + "expected": { + "indent": 2 + }, + "actual": { + "h_align": "general", + "v_align": "bottom", + "indent": 2.0 + }, + "notes": null, + "diagnostics": [], + "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": "borders", + "library": "sheetjs", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "thin_all": { + "read": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thin_all", + "sheet": "borders", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thin all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "medium_all", + "sheet": "borders", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - medium all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "medium", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "thick_all", + "sheet": "borders", + "cell": "B4" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - thick all edges" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thick", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "double", + "sheet": "borders", + "cell": "B5" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - double line" + }, + "write": { + "passed": false, + "expected": { + "border_style": "double", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dashed", + "sheet": "borders", + "cell": "B6" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dashed" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashed", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dotted", + "sheet": "borders", + "cell": "B7" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dotted" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dotted", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot", + "sheet": "borders", + "cell": "B8" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDot", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "dash_dot_dot", + "sheet": "borders", + "cell": "B9" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - dash-dot-dot" + }, + "write": { + "passed": false, + "expected": { + "border_style": "dashDotDot", + "border_color": "#000000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "top_only", + "sheet": "borders", + "cell": "B10" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - top only" + }, + "write": { + "passed": false, + "expected": { + "border_top": "thin", + "border_bottom": null, + "border_left": null, + "border_right": null + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "bottom_only", + "sheet": "borders", + "cell": "B11" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - bottom only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": "thin", + "border_left": null, + "border_right": null + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "left_only", + "sheet": "borders", + "cell": "B12" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - left only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": "thin", + "border_right": null + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "right_only", + "sheet": "borders", + "cell": "B13" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - right only" + }, + "write": { + "passed": false, + "expected": { + "border_top": null, + "border_bottom": null, + "border_left": null, + "border_right": "thin" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_up", + "sheet": "borders", + "cell": "B14" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal up" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_down", + "sheet": "borders", + "cell": "B15" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal down" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_down": "thin" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "diagonal_both", + "sheet": "borders", + "cell": "B16" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - diagonal both" + }, + "write": { + "passed": false, + "expected": { + "border_diagonal_up": "thin", + "border_diagonal_down": "thin" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_red", + "sheet": "borders", + "cell": "B17" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - red color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#FF0000" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_blue", + "sheet": "borders", + "cell": "B18" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - blue color" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#0000FF" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "color_custom", + "sheet": "borders", + "cell": "B19" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Border - custom color (#8B4513)" + }, + "write": { + "passed": false, + "expected": { + "border_style": "thin", + "border_color": "#8B4513" + }, + "actual": { + "error": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_styles", + "sheet": "borders", + "cell": "B20" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "borders", + "operation": "read", + "test_case_id": "mixed_colors", + "sheet": "borders", + "cell": "B21" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support cell_border: SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles" + }, + "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: sheetjs does not support cell_border: SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles", + "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": "exceljs", + "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": "libreoffice", + "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": "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": "dimensions", + "library": "sheetjs", + "scores": { + "read": 3, + "write": 1 + }, + "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": 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": true, + "expected": { + "row_height": 45 + }, + "actual": { + "row_height": 45.0 + }, + "notes": null, + "diagnostics": [], + "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": 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": "exceljs", + "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": "libreoffice", + "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": 19.998 + }, + "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': 19.998}", + "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": 7.998 + }, + "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': 7.998}", + "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": "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": "multiple_sheets", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "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": "merged_cells", + "library": "sheetjs", + "scores": { + "read": 3, + "write": 2 + }, + "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": false, + "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": 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': 'Fill', '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": "exceljs", + "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": "libreoffice", + "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": "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": 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": "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": "conditional_formatting", + "library": "sheetjs", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_cell_gt", + "sheet": "conditional_formatting", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_formula_cross_sheet", + "sheet": "conditional_formatting", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_text_contains", + "sheet": "conditional_formatting", + "cell": "B4" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_data_bar", + "sheet": "conditional_formatting", + "cell": "B5" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: data bar" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "dataBar", + "priority": 4 + } + }, + "actual": { + "error": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_color_scale", + "sheet": "conditional_formatting", + "cell": "B6" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "CF: 3-color scale" + }, + "write": { + "passed": false, + "expected": { + "cf_rule": { + "range": "B2:B6", + "rule_type": "colorScale", + "priority": 5 + } + }, + "actual": { + "error": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "conditional_formatting", + "operation": "read", + "test_case_id": "cf_stop_if_true", + "sheet": "conditional_formatting", + "cell": "B7" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support conditional_formats: SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no " + }, + "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: sheetjs does not support conditional_format: SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + "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": "exceljs", + "scores": { + "read": 2, + "write": 2 + }, + "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": 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": null, + "format": { + "bg_color": "#FF0000" + } + } + }, + "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': None, 'format': {'bg_color': '#FF0000'}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata 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": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": null, + "format": { + "bg_color": "#FF0000" + } + } + }, + "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={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': None, 'format': {'bg_color': '#FF0000'}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata 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": "libreoffice", + "scores": { + "read": 2, + "write": 0 + }, + "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": 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": { + "bg_color": "#000000" + } + } + }, + "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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'cellIs', 'operator': 'greaterThan', 'formula': '5', 'format': {'bg_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": "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": 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": { + "bg_color": "#000000" + } + } + }, + "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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=Ref!$A$1>5', 'format': {'bg_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": "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": 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": { + "bg_color": "#000000" + } + } + }, + "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={'cf_rule': {'range': 'B2:B6', 'rule_type': 'expression', 'formula': '=ISNUMBER(SEARCH(\"foo\",B2))', 'format': {'bg_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": "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": 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": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": null, + "format": { + "bg_color": "#FF0000" + } + } + }, + "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': None, 'format': {'bg_color': '#FF0000'}}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata 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": { + "cf_rule": { + "range": "B7:B9", + "rule_type": "cellIs", + "operator": "lessThan", + "formula": "3", + "stop_if_true": null, + "format": { + "bg_color": "#000000" + } + } + }, + "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={'cf_rule': {'range': 'B7:B9', 'rule_type': 'cellIs', 'operator': 'lessThan', 'formula': '3', 'stop_if_true': None, 'format': {'bg_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": "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": "data_validation", + "library": "sheetjs", + "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": "sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_csv", + "sheet": "data_validation", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no " + }, + "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: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "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": "sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_list_range", + "sheet": "data_validation", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: list from range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B3", + "validation_type": "list", + "formula1": "=$D$2:$D$4" + } + }, + "actual": { + "error": "sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no " + }, + "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: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "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": "sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_cross_sheet", + "sheet": "data_validation", + "cell": "B4" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: cross-sheet named range" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B4", + "validation_type": "list", + "formula1": "=RegionList" + } + }, + "actual": { + "error": "sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no " + }, + "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: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "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": "sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_custom_formula", + "sheet": "data_validation", + "cell": "B5" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "DV: custom formula" + }, + "write": { + "passed": false, + "expected": { + "validation": { + "range": "B5", + "validation_type": "custom", + "formula1": "=B5>C5" + } + }, + "actual": { + "error": "sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no " + }, + "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: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "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": "sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips " + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "data_validation", + "operation": "read", + "test_case_id": "dv_whole_between", + "sheet": "data_validation", + "cell": "B6" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support data_validations: SheetJS CE has no data validation API; the XLSX reader skips ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX reader skips ", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no " + }, + "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: sheetjs does not support data_validation: SheetJS CE has no data validation API; the XLSX writer emits no ", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE has no data validation API; the XLSX writer emits no ", + "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": "exceljs", + "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": "libreoffice", + "scores": { + "read": 3, + "write": 2 + }, + "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": 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": 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": "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": "hyperlinks", + "library": "sheetjs", + "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": "exceljs", + "scores": { + "read": 0, + "write": 2 + }, + "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": "Example Docs", + "tooltip": null, + "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': 'Example Docs', 'tooltip': None, '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": {}, + "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": { + "hyperlink": { + "cell": "B3", + "target": "Targets!A1#Targets!A1", + "display": "Go Target", + "tooltip": "Jump to target", + "internal": false + } + }, + "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={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1#Targets!A1', 'display': 'Go Target', 'tooltip': 'Jump to target', '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: 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": "Email", + "tooltip": null, + "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': 'Email', 'tooltip': None, '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": "Search", + "tooltip": null, + "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': 'Search', 'tooltip': None, '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": "libreoffice", + "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": { + "hyperlink": { + "cell": "B2", + "target": "https://example.com/docs", + "display": "Example Docs", + "tooltip": null, + "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': 'Example Docs', 'tooltip': None, '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": 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": "Example Docs", + "tooltip": null, + "internal": false + } + }, + "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={'hyperlink': {'cell': 'B2', 'target': 'https://example.com/docs', 'display': 'Example Docs', 'tooltip': None, '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" + } + }, + "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": "Go Target", + "tooltip": null, + "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': 'Go Target', 'tooltip': None, '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": 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": "Go Target", + "tooltip": null, + "internal": true + } + }, + "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={'hyperlink': {'cell': 'B3', 'target': 'Targets!A1', 'display': 'Go Target', 'tooltip': None, '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" + } + }, + "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": "Email", + "tooltip": null, + "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': 'Email', 'tooltip': None, '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": 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": "Email", + "tooltip": null, + "internal": false + } + }, + "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={'hyperlink': {'cell': 'B4', 'target': 'mailto:test@example.com', 'display': 'Email', 'tooltip': None, '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" + } + }, + "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": "Search", + "tooltip": null, + "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': 'Search', 'tooltip': None, '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": 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": "Search", + "tooltip": null, + "internal": false + } + }, + "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={'hyperlink': {'cell': 'B5', 'target': 'https://example.com/search?q=excel%20bench&sort=desc#section-2', 'display': 'Search', 'tooltip': None, '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" + } + } + }, + "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": "images", + "library": "sheetjs", + "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": "sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed" + }, + "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: sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "probable_cause": "SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "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": "sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written)" + }, + "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: sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written)", + "probable_cause": "SheetJS CE cannot embed images (drawing parts are not written)", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot embed images (drawing parts are not written)", + "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": "sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed" + }, + "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: sheetjs does not support images: SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "probable_cause": "SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + "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": "sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written)" + }, + "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: sheetjs does not support image: SheetJS CE cannot embed images (drawing parts are not written)", + "probable_cause": "SheetJS CE cannot embed images (drawing parts are not written)", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot embed images (drawing parts are not written)", + "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": "exceljs", + "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": "exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_one_cell", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')", + "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": {}, + "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": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "images", + "operation": "read", + "test_case_id": "image_two_cell_offset", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')", + "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": {}, + "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": "libreoffice", + "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": "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": "pivot_tables", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "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": "comments", + "library": "sheetjs", + "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": "exceljs", + "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": "libreoffice", + "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": "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": "freeze_panes", + "library": "sheetjs", + "scores": { + "read": 0, + "write": 0 + }, + "test_cases": { + "freeze_b2": { + "read": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_b2", + "sheet": "FreezeB2", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "basic", + "label": "Freeze panes at B2" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "B2" + } + }, + "actual": { + "error": "sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set" + }, + "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: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "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": "sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "freeze_d5", + "sheet": "FreezeD5", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Freeze panes at D5" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "freeze", + "top_left_cell": "D5" + } + }, + "actual": { + "error": "sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set" + }, + "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: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "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": "sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "freeze_panes", + "operation": "read", + "test_case_id": "split_2x1", + "sheet": "SplitPanes", + "cell": "B4" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support freeze_panes: SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Split panes row=2 col=1" + }, + "write": { + "passed": false, + "expected": { + "freeze": { + "mode": "split", + "x_split": 1, + "y_split": 2 + } + }, + "actual": { + "error": "sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set" + }, + "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: sheetjs does not support freeze: SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + "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": "exceljs", + "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": "libreoffice", + "scores": { + "read": 3, + "write": 2 + }, + "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": 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": 2, + "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": 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": "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': '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" + }, + "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": "named_ranges", + "library": "sheetjs", + "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": "exceljs", + "scores": { + "read": 2, + "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": 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": "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': '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" + }, + "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": "libreoffice", + "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": "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": 2, + "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": false, + "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": false + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "Expected values did not match actual values: 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': False}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata 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": 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": "tables", + "library": "sheetjs", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": "tables", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": "tables", + "cell": "B3" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": "tables", + "cell": "B4" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": "tables", + "cell": "B5" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "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": "sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": "tables", + "cell": "B7" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support tables: SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + "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": "sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support table: SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "importance": "edge", + "label": "Table: with autoFilter" + } + } + }, + "notes": null + }, + { + "feature": "tables", + "library": "exceljs", + "scores": { + "read": 0, + "write": 3 + }, + "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": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_basic", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_with_totals", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": false, + "expected": { + "table": { + "name": "PlainTable", + "ref": "E13:F16", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [ + "Key", + "Value" + ] + } + }, + "actual": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_no_style", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": false, + "expected": { + "table": { + "name": "SingleCol", + "ref": "E18:E21", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium2", + "columns": [ + "Score" + ] + } + }, + "actual": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_col", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_single_row", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": false, + "expected": { + "table": { + "name": "Filtered", + "ref": "E25:G28", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "Region", + "Sales", + "Year" + ], + "autofilter": true + } + }, + "actual": { + "error": "exceljs read_model failed: Cannot read properties of undefined (reading 'name')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "tables", + "operation": "read", + "test_case_id": "tbl_autofilter", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'name')", + "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": 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": "libreoffice", + "scores": { + "read": 3, + "write": 2 + }, + "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": false, + "expected": { + "table": { + "name": "EmptyTable", + "ref": "E23:G23", + "header_row": true, + "totals_row": false, + "style": "TableStyleMedium9", + "columns": [ + "A", + "B", + "C" + ] + } + }, + "actual": { + "table": { + "name": "EmptyTable", + "ref": "not_found", + "header_row": true, + "totals_row": false, + "style": null, + "columns": [] + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "tables", + "operation": "write", + "test_case_id": "tbl_single_row", + "sheet": "tables", + "cell": "B6" + }, + "adapter_message": "Expected values did not match actual values: expected={'table': {'name': 'EmptyTable', 'ref': 'E23:G23', 'header_row': True, 'totals_row': False, 'style': 'TableStyleMedium9', 'columns': ['A', 'B', 'C']}}, actual={'table': {'name': 'EmptyTable', 'ref': 'not_found', 'header_row': True, 'totals_row': False, 'style': None, 'columns': []}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": "style_drift", + "suggested_next_step": "inspect styles.xml and the adapter's style mapping", + "explanation": { + "code": "style_drift", + "summary": "cell style metadata 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)" + } + }, + "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": "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": "sheet_protection", + "library": "sheetjs", + "scores": { + "read": 0, + "write": 3 + }, + "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": "sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "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": "UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": 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": "sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "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": "UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": 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": "sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "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": "UnsupportedAdapterOperationError: sheetjs does not support sheet_protection: SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + "next_step": "treat as unsupported capability, not a semantic regression", + "tag": "unsupported" + } + } + ], + "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": "exceljs", + "scores": { + "read": 1, + "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": 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": { + "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": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': False, 'format_cells': True, 'insert_rows': True, 'select_locked_cells': False, 'select_unlocked_cells': False, 'sort': True, 'auto_filter': True}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "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": "libreoffice", + "scores": { + "read": 0, + "write": 2 + }, + "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": { + "protection": { + "auto_filter": null, + "format_cells": null, + "insert_rows": null, + "password_hash_present": false, + "protected": true, + "select_locked_cells": null, + "select_unlocked_cells": null, + "sort": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_basic", + "sheet": "sheet_protection_basic", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': False, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': 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": "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": 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": { + "protection": { + "auto_filter": null, + "format_cells": null, + "insert_rows": null, + "password_hash_present": true, + "protected": true, + "select_locked_cells": null, + "select_unlocked_cells": null, + "sort": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_password", + "sheet": "sheet_protection_password", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': True, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': 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": "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": 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": { + "protection": { + "auto_filter": null, + "format_cells": null, + "insert_rows": null, + "password_hash_present": false, + "protected": true, + "select_locked_cells": null, + "select_unlocked_cells": null, + "sort": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "read", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': {'auto_filter': None, 'format_cells': None, 'insert_rows': None, 'password_hash_present': False, 'protected': True, 'select_locked_cells': None, 'select_unlocked_cells': None, 'sort': None}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "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": { + "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": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "sheet_protection", + "operation": "write", + "test_case_id": "prot_granular", + "sheet": "sheet_protection_granular", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': True, 'insert_rows': True, 'select_locked_cells': False, 'select_unlocked_cells': False, 'sort': True, 'auto_filter': True}}", + "probable_cause": "Adapter returned a value that differs from benchmark expectations.", + "root_cause_code": null, + "suggested_next_step": null, + "explanation": null + } + ], + "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": "page_setup", + "library": "sheetjs", + "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": { + "page_setup": {} + }, + "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': {}}", + "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": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "write", + "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': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, '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" + } + }, + "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": { + "page_setup": {} + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "read", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {}}", + "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: 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": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': None, 'fit_to_width': None, 'fit_to_height': None, 'scale': None, '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: 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": { + "print_title_rows": "$1:$2" + } + }, + "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': {'print_title_rows': '$1:$2'}}", + "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": { + "page_setup": { + "orientation": null, + "fit_to_width": null, + "fit_to_height": null, + "scale": null, + "print_title_rows": "$1:$2", + "header_center": null, + "footer_center": null + } + }, + "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': '$1:$2', '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": "edge", + "label": "Page setup: print titles + header/footer" + } + } + }, + "notes": null + }, + { + "feature": "page_setup", + "library": "exceljs", + "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": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": 1, + "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': 1, '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": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": 1, + "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": "write", + "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': 1, '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" + } + }, + "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": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": 1, + "fit_to_height": 1, + "scale": 75, + "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_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, '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: 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": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": 1, + "fit_to_height": 1, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, '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: 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": "portrait", + "fit_to_width": 1, + "fit_to_height": 1, + "scale": 100, + "print_title_rows": "$1:$2", + "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': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 100, 'print_title_rows': '$1:$2', '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": "libreoffice", + "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": { + "fit_to_height": null, + "fit_to_width": null, + "footer_center": null, + "header_center": null, + "orientation": "landscape", + "print_title_rows": null, + "scale": 100 + } + }, + "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': {'fit_to_height': None, 'fit_to_width': None, 'footer_center': None, 'header_center': None, 'orientation': 'landscape', 'print_title_rows': None, 'scale': 100}}", + "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": { + "page_setup": { + "orientation": "landscape", + "fit_to_width": 1, + "fit_to_height": 0, + "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": "write", + "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': 0, '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" + } + }, + "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": { + "fit_to_height": null, + "fit_to_width": null, + "footer_center": null, + "header_center": null, + "orientation": "portrait", + "print_title_rows": null, + "scale": 75 + } + }, + "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": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": 1, + "fit_to_height": 1, + "scale": 75, + "print_title_rows": null, + "header_center": null, + "footer_center": null + } + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "page_setup", + "operation": "write", + "test_case_id": "page_setup_scale", + "sheet": "page_setup_scale", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'page_setup': {'orientation': 'portrait', 'fit_to_width': None, 'fit_to_height': None, 'scale': 75, 'print_title_rows': None, 'header_center': None, 'footer_center': None}}, actual={'page_setup': {'orientation': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 75, '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: 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": { + "fit_to_height": null, + "fit_to_width": null, + "footer_center": "Page &P", + "header_center": "ExcelBench Report", + "orientation": "portrait", + "print_title_rows": "$1:$2", + "scale": 100 + } + }, + "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': {'fit_to_height': None, 'fit_to_width': None, 'footer_center': 'Page &P', 'header_center': 'ExcelBench Report', 'orientation': 'portrait', 'print_title_rows': '$1:$2', 'scale': 100}}", + "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": { + "page_setup": { + "orientation": "portrait", + "fit_to_width": 1, + "fit_to_height": 1, + "scale": 100, + "print_title_rows": "$1:$2", + "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': 'portrait', 'fit_to_width': 1, 'fit_to_height': 1, 'scale': 100, 'print_title_rows': '$1:$2', '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": "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": 0 + }, + "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": false, + "expected": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "H12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str'" + }, + "notes": "Write failed: TypeError", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str'", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "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" + } + }, + "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": false, + "expected": { + "charts": [ + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "P12", + "data_ref": "E2:E8", + "categories_ref": "F2:F8" + } + ] + }, + "actual": { + "error": "argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str'" + }, + "notes": "Write failed: TypeError", + "diagnostics": [ + { + "category": "invalid_input", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "TypeError: argument 'anchor_a1': 'TwoCellAnchor' object is not an instance of 'str'", + "probable_cause": "Adapter could not create or save a workbook for this feature.", + "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" + } + } + }, + "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 + }, + { + "feature": "chart_anchor", + "library": "sheetjs", + "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": "sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets", + "probable_cause": "SheetJS CE does not parse charts or drawing anchors in worksheets", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse charts or drawing anchors in worksheets", + "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": "sheetjs does not support chart: SheetJS CE cannot create charts" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support chart: SheetJS CE cannot create charts", + "probable_cause": "SheetJS CE cannot create charts", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create charts", + "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": "sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets" + }, + "notes": "Exception: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support chart_anchors: SheetJS CE does not parse charts or drawing anchors in worksheets", + "probable_cause": "SheetJS CE does not parse charts or drawing anchors in worksheets", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE does not parse charts or drawing anchors in worksheets", + "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": "sheetjs does not support chart: SheetJS CE cannot create charts" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: sheetjs does not support chart: SheetJS CE cannot create charts", + "probable_cause": "SheetJS CE cannot create charts", + "root_cause_code": "unsupported_feature", + "suggested_next_step": "treat as unsupported capability, not a semantic regression", + "explanation": { + "code": "unsupported_feature", + "summary": "adapter reported this operation as unsupported", + "probable_cause": "SheetJS CE cannot create charts", + "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": "exceljs", + "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": "exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')", + "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": "exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API", + "probable_cause": "ExcelJS 4.4.0 has no chart creation 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": "ExcelJS 4.4.0 has no chart creation API", + "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": "exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')" + }, + "notes": "Failed to open workbook", + "diagnostics": [ + { + "category": "internal", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "HelperError: exceljs read_model failed: Cannot read properties of undefined (reading 'anchors')", + "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": "exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API" + }, + "notes": "Write failed: UnsupportedAdapterOperationError", + "diagnostics": [ + { + "category": "unsupported_feature", + "severity": "warning", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": null, + "cell": null + }, + "adapter_message": "UnsupportedAdapterOperationError: exceljs does not support chart: ExcelJS 4.4.0 has no chart creation API", + "probable_cause": "ExcelJS 4.4.0 has no chart creation 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": "ExcelJS 4.4.0 has no chart creation API", + "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": "libreoffice", + "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": { + "charts": [ + { + "anchor_type": "twoCell", + "from": "B2", + "to": "G11", + "type": "bar" + }, + { + "anchor_type": "twoCell", + "from": "J2", + "to": "O11", + "type": "line" + } + ] + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'charts': [{'type': 'bar', 'anchor_type': 'twoCell', 'from': 'B2', 'to': 'H12', 'data_ref': 'E2:E8', 'categories_ref': 'F2:F8'}]}, actual={'charts': [{'anchor_type': 'twoCell', 'from': 'B2', 'to': 'G11', 'type': 'bar'}, {'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11', 'type': 'line'}]}", + "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": "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": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "G11" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "O11" + } + ] + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_bar", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': 'G11'}, {'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11'}]}", + "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": "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": { + "charts": [ + { + "anchor_type": "twoCell", + "from": "B2", + "to": "G11", + "type": "bar" + }, + { + "anchor_type": "twoCell", + "from": "J2", + "to": "O11", + "type": "line" + } + ] + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "read", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: expected={'charts': [{'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'P12', 'data_ref': 'E2:E8', 'categories_ref': 'F2:F8'}]}, actual={'charts': [{'anchor_type': 'twoCell', 'from': 'B2', 'to': 'G11', 'type': 'bar'}, {'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11', 'type': 'line'}]}", + "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": "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": { + "charts": [ + { + "type": "bar", + "anchor_type": "twoCell", + "from": "B2", + "to": "G11" + }, + { + "type": "line", + "anchor_type": "twoCell", + "from": "J2", + "to": "O11" + } + ] + }, + "notes": "Incorrect result", + "diagnostics": [ + { + "category": "data_mismatch", + "severity": "error", + "location": { + "feature": "chart_anchor", + "operation": "write", + "test_case_id": "chart_line", + "sheet": "chart_anchor", + "cell": "B2" + }, + "adapter_message": "Expected values did not match actual values: 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': 'G11'}, {'type': 'line', 'anchor_type': 'twoCell', 'from': 'J2', 'to': 'O11'}]}", + "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": "Chart: line with twoCell anchor" + } + } + }, + "notes": null + } + ] +} \ No newline at end of file diff --git a/results/perf/README.md b/results/perf/README.md index b00e987..70df5e8 100644 --- a/results/perf/README.md +++ b/results/perf/README.md @@ -7,6 +7,8 @@ *Commit: 0aeaf16* *Config: warmup=3 iters=25 iteration_policy=fixed breakdown=False* +> **Superseded for WolfXL.** The `wolfxl` columns in this snapshot measured private backend objects in `wolfxl._rust` (`cal=0.4.0+rxw=0.79.4`), not WolfXL's public API, so they are not comparable with the other libraries' public-API numbers. Use the [2026-10-02 perf snapshot](../../results-2026-10-02/perf/README.md), which measures WolfXL 2.0.5 through `wolfxl.load_workbook` and `wolfxl.Workbook`. + ## Notes These numbers measure only the library under test. Write timings do NOT include oracle verification. diff --git a/src/excelbench/cli.py b/src/excelbench/cli.py index 954be37..17a1a4b 100644 --- a/src/excelbench/cli.py +++ b/src/excelbench/cli.py @@ -2060,8 +2060,8 @@ def mutation( """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. + measures wall time, peak RSS, and whether the output's workbook content + equals the template's content with exactly those two edits applied. """ from excelbench.harness.mutation import run_mutation_suite @@ -2075,13 +2075,16 @@ def mutation( try: results = run_mutation_suite(template, output_dir, repeats=repeats) - from excelbench.results.mutation_renderer import render_mutation_report + from excelbench.results.mutation_renderer import ( + mutation_verdict, + 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']}" + f" {name}: {engine['wall_ms_median']}ms, features preserved " + f"{engine['feature_preservation']}, {mutation_verdict(engine)}" ) console.print() console.print(f"[green]✓ Mutation results written to {output_dir}[/green]") diff --git a/src/excelbench/harness/adapters/__init__.py b/src/excelbench/harness/adapters/__init__.py index eb09176..be4a6be 100644 --- a/src/excelbench/harness/adapters/__init__.py +++ b/src/excelbench/harness/adapters/__init__.py @@ -202,6 +202,30 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: ZavoraAdapter: AdapterClass | None = None else: ZavoraAdapter = _ZavoraAdapter +try: + from excelbench.harness.adapters.sheetjs_adapter import ( + SheetjsAdapter as _SheetjsAdapter, + ) +except ImportError: + SheetjsAdapter: AdapterClass | None = None +else: + SheetjsAdapter = _SheetjsAdapter +try: + from excelbench.harness.adapters.exceljs_adapter import ( + ExceljsAdapter as _ExceljsAdapter, + ) +except ImportError: + ExceljsAdapter: AdapterClass | None = None +else: + ExceljsAdapter = _ExceljsAdapter +try: + from excelbench.harness.adapters.libreoffice_adapter import ( + LibreofficeAdapter as _LibreofficeAdapter, + ) +except ImportError: + LibreofficeAdapter: AdapterClass | None = None +else: + LibreofficeAdapter = _LibreofficeAdapter __all__ = [ @@ -254,6 +278,12 @@ def _is_available_adapter(adapter: AdapterClass | None) -> bool: __all__.append("ExcelizeAdapter") if ZavoraAdapter is not None: __all__.append("ZavoraAdapter") +if SheetjsAdapter is not None: + __all__.append("SheetjsAdapter") +if ExceljsAdapter is not None: + __all__.append("ExceljsAdapter") +if LibreofficeAdapter is not None: + __all__.append("LibreofficeAdapter") def get_all_adapters() -> list[ExcelAdapter]: @@ -301,4 +331,10 @@ def get_all_adapters() -> list[ExcelAdapter]: adapters.append(ExcelizeAdapter()) if ZavoraAdapter is not None and _is_available_adapter(ZavoraAdapter): adapters.append(ZavoraAdapter()) + if SheetjsAdapter is not None and _is_available_adapter(SheetjsAdapter): + adapters.append(SheetjsAdapter()) + if ExceljsAdapter is not None and _is_available_adapter(ExceljsAdapter): + adapters.append(ExceljsAdapter()) + if LibreofficeAdapter is not None and _is_available_adapter(LibreofficeAdapter): + adapters.append(LibreofficeAdapter()) return adapters diff --git a/src/excelbench/harness/adapters/exceljs_adapter.py b/src/excelbench/harness/adapters/exceljs_adapter.py new file mode 100644 index 0000000..89f5664 --- /dev/null +++ b/src/excelbench/harness/adapters/exceljs_adapter.py @@ -0,0 +1,22 @@ +"""Adapter for ExcelJS (npm ``exceljs``) via the ExcelJS external helper.""" + +from __future__ import annotations + +from pathlib import Path + +from excelbench.harness.adapters.json_model_adapter import JsonModelAdapter +from excelbench.harness.external_oracles import ( + ExternalOracleTool, + external_oracle_catalog, +) + + +class ExceljsAdapter(JsonModelAdapter): + """ExcelJS read/write/modify through ``tools/external-oracles/exceljs``.""" + + LIBRARY_NAME = "exceljs" + LANGUAGE = "javascript" + + @classmethod + def tool(cls) -> ExternalOracleTool: + return external_oracle_catalog(repo_root=Path(__file__).resolve().parents[4])["exceljs"] diff --git a/src/excelbench/harness/adapters/json_model_adapter.py b/src/excelbench/harness/adapters/json_model_adapter.py new file mode 100644 index 0000000..6d052d6 --- /dev/null +++ b/src/excelbench/harness/adapters/json_model_adapter.py @@ -0,0 +1,554 @@ +"""Shared adapter base for libraries driven through an external JSON helper. + +Non-Python libraries (SheetJS, ExcelJS, LibreOffice UNO) cannot hand Python a +live workbook object. Their helpers instead speak a small JSON protocol over +stdin/stdout (the same transport as ``external_oracles``): + +``describe`` + Returns ``{"library", "version", "capabilities", "unsupported_write"}``. +``read_model`` (``input_path``) + Loads the workbook with the library's own read API and returns + ``{"model": ...}``: a normalized snapshot of everything the library + exposed. Values the library does not surface are simply absent, and + features it cannot read at all are listed in ``model["unsupported"]``. +``write_model`` (``output_path``, ``payload.ops``) + Replays the recorded adapter calls through the library's write API. +``mutate`` (``input_path``, ``output_path``, ``payload.mutations``) + Opens an existing workbook, sets cell values, and saves it. + +The Python side only translates the snapshot into ExcelBench models; it never +fills in values the helper did not report. +""" + +from __future__ import annotations + +import json +from dataclasses import dataclass, field +from datetime import date, datetime +from pathlib import Path +from typing import Any, ClassVar + +from excelbench.harness.adapters.base import ExcelAdapter +from excelbench.harness.external_oracles import ( + ExternalOracleRequest, + ExternalOracleTool, + run_external_oracle, +) +from excelbench.models import ( + BorderEdge, + BorderInfo, + BorderStyle, + CellFormat, + CellType, + CellValue, + LibraryInfo, +) + +JSONDict = dict[str, Any] + +_FORMAT_FIELDS = ( + "bold", + "italic", + "underline", + "strikethrough", + "font_name", + "font_size", + "font_color", + "bg_color", + "number_format", + "h_align", + "v_align", + "wrap", + "rotation", + "indent", +) +_BORDER_EDGES = ("top", "bottom", "left", "right", "diagonal_up", "diagonal_down") +# Stored column widths carry font-metric padding; strip the same known paddings +# the openpyxl adapter strips so every reader reports display character width. +_COLUMN_WIDTH_PADDINGS = (0.83203125, 0.7109375) + + +class HelperError(RuntimeError): + """Raised when an external adapter helper reports a failure.""" + + +@dataclass +class ModelWorkbook: + """Read-side handle: the normalized snapshot returned by ``read_model``.""" + + model: JSONDict + sheets: dict[str, JSONDict] = field(init=False) + + def __post_init__(self) -> None: + self.sheets = { + str(sheet["name"]): sheet for sheet in self.model.get("sheets", []) + } + + +@dataclass +class OpLog: + """Write-side handle: adapter calls recorded for one ``write_model`` replay.""" + + ops: list[JSONDict] = field(default_factory=list) + + +def _json_safe(value: Any) -> Any: + if isinstance(value, datetime): + return value.isoformat(timespec="seconds") + if isinstance(value, date): + return value.isoformat() + if isinstance(value, dict): + return {str(k): _json_safe(v) for k, v in value.items()} + if isinstance(value, (list, tuple)): + return [_json_safe(v) for v in value] + if hasattr(value, "value") and type(value).__module__.startswith("excelbench"): + return value.value + return value + + +def _cell_value_from_model(entry: JSONDict | None) -> CellValue: + if not entry: + return CellValue(type=CellType.BLANK) + cell_type = CellType(str(entry.get("type", "blank"))) + value = entry.get("value") + formula = entry.get("formula") + if cell_type == CellType.BLANK: + return CellValue(type=CellType.BLANK) + if cell_type == CellType.DATE and isinstance(value, str): + return CellValue(type=cell_type, value=date.fromisoformat(value[:10])) + if cell_type == CellType.DATETIME and isinstance(value, str): + return CellValue(type=cell_type, value=datetime.fromisoformat(value[:19])) + if cell_type == CellType.FORMULA: + text = str(formula if formula is not None else value or "") + if text and not text.startswith("="): + text = f"={text}" + return CellValue(type=cell_type, value=text, formula=text) + return CellValue(type=cell_type, value=value) + + +def _border_edge(entry: Any) -> BorderEdge | None: + if not isinstance(entry, dict): + return None + style = entry.get("style") + if not style or style == "none": + return None + try: + border_style = BorderStyle(str(style)) + except ValueError: + border_style = BorderStyle.THIN + color = entry.get("color") or "#000000" + return BorderEdge(style=border_style, color=str(color)) + + +def _normalize_column_width(width: Any) -> float | None: + if not isinstance(width, (int, float)): + return None + width_f = float(width) + frac = width_f % 1 + for padding in _COLUMN_WIDTH_PADDINGS: + if abs(frac - padding) < 0.01: + width_f -= padding + break + return round(width_f, 4) + + +def _normalize_refers_to(value: Any) -> str: + if value is None: + return "" + raw = str(value).lstrip("=") + if "!" not in raw: + return raw + sheet_part, addr = raw.split("!", 1) + 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}" + + +class JsonModelAdapter(ExcelAdapter): + """Adapter whose reads/writes are executed by an external JSON helper.""" + + LIBRARY_NAME: ClassVar[str] = "" + LANGUAGE: ClassVar[str] = "external" + TIMEOUT_SECONDS: ClassVar[float] = 120.0 + _describe_cache: ClassVar[dict[str, JSONDict]] = {} + + @classmethod + def tool(cls) -> ExternalOracleTool: + """Return the helper descriptor.""" + raise NotImplementedError + + @classmethod + def is_available(cls) -> bool: + """Return whether the helper runtime and dependencies are installed.""" + return cls.tool().is_available() + + @classmethod + def call_helper( + cls, + operation: str, + *, + payload: JSONDict | None = None, + input_path: Path | None = None, + output_path: Path | None = None, + ) -> JSONDict: + """Run one helper operation and return its JSON payload.""" + tool = cls.tool() + result = run_external_oracle( + tool, + ExternalOracleRequest( + fixture_id=f"{tool.name}-adapter", + operation=operation, + payload=payload or {}, + input_path=input_path, + output_path=output_path, + ), + timeout_seconds=cls.TIMEOUT_SECONDS, + ) + if not result.passed: + message = ( + result.payload.get("message") + or result.notes + or result.stderr.strip() + or result.stdout.strip() + or "helper failed without output" + ) + raise HelperError(f"{tool.name} {operation} failed: {message}") + return result.payload + + @classmethod + def describe(cls) -> JSONDict: + """Return cached library identity and write-support declarations.""" + key = cls.__name__ + if key not in cls._describe_cache: + cls._describe_cache[key] = cls.call_helper("describe") + return cls._describe_cache[key] + + @property + def name(self) -> str: + # Static so adapter selection never spawns the helper. + return self.LIBRARY_NAME + + @property + def info(self) -> LibraryInfo: + described = self.describe() + if described.get("library") != self.LIBRARY_NAME: + raise HelperError( + f"helper identifies as {described.get('library')!r}, expected {self.LIBRARY_NAME!r}" + ) + return LibraryInfo( + name=self.LIBRARY_NAME, + version=str(described["version"]), + language=self.LANGUAGE, + capabilities=set(described.get("capabilities", ["read", "write"])), + ) + + # ========================================================================= + # Read side + # ========================================================================= + + def open_workbook(self, path: Path) -> ModelWorkbook: + payload = self.call_helper("read_model", input_path=Path(path).resolve()) + return ModelWorkbook(payload["model"]) + + def close_workbook(self, workbook: Any) -> None: + return None + + def get_sheet_names(self, workbook: ModelWorkbook) -> list[str]: + return list(workbook.sheets) + + def _sheet(self, workbook: ModelWorkbook, sheet: str) -> JSONDict: + try: + return workbook.sheets[sheet] + except KeyError as exc: + raise KeyError(f"Worksheet not found: {sheet}") from exc + + def _require_read(self, workbook: ModelWorkbook, feature: str) -> None: + reason = workbook.model.get("unsupported", {}).get(feature) + if reason: + self.unsupported_operation(feature, str(reason)) + + def _sheet_list( + self, workbook: ModelWorkbook, sheet: str, key: str + ) -> list[JSONDict]: + self._require_read(workbook, key) + return [dict(item) for item in self._sheet(workbook, sheet).get(key, [])] + + def _cell_entry(self, workbook: ModelWorkbook, sheet: str, cell: str) -> JSONDict: + entry: JSONDict = ( + self._sheet(workbook, sheet).get("cells", {}).get(cell.upper(), {}) + ) + return entry + + def read_cell_value( + self, workbook: ModelWorkbook, sheet: str, cell: str + ) -> CellValue: + self._require_read(workbook, "cell_values") + return _cell_value_from_model( + self._cell_entry(workbook, sheet, cell).get("value") + ) + + def read_cell_format( + self, workbook: ModelWorkbook, sheet: str, cell: str + ) -> CellFormat: + self._require_read(workbook, "cell_format") + fmt = self._cell_entry(workbook, sheet, cell).get("format") or {} + return CellFormat(**{key: fmt.get(key) for key in _FORMAT_FIELDS}) + + def read_cell_border( + self, workbook: ModelWorkbook, sheet: str, cell: str + ) -> BorderInfo: + self._require_read(workbook, "cell_border") + border = self._cell_entry(workbook, sheet, cell).get("border") or {} + return BorderInfo( + **{edge: _border_edge(border.get(edge)) for edge in _BORDER_EDGES} + ) + + def read_row_height( + self, workbook: ModelWorkbook, sheet: str, row: int + ) -> float | None: + self._require_read(workbook, "row_heights") + height = self._sheet(workbook, sheet).get("row_heights", {}).get(str(row)) + return float(height) if isinstance(height, (int, float)) else None + + def read_column_width( + self, workbook: ModelWorkbook, sheet: str, column: str + ) -> float | None: + self._require_read(workbook, "column_widths") + widths = self._sheet(workbook, sheet).get("column_widths", {}) + return _normalize_column_width(widths.get(column.upper())) + + def read_merged_ranges(self, workbook: ModelWorkbook, sheet: str) -> list[str]: + self._require_read(workbook, "merged_ranges") + return [ + str(rng) for rng in self._sheet(workbook, sheet).get("merged_ranges", []) + ] + + def read_conditional_formats( + self, workbook: ModelWorkbook, sheet: str + ) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "conditional_formats") + + def read_data_validations( + self, workbook: ModelWorkbook, sheet: str + ) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "data_validations") + + def read_hyperlinks(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "hyperlinks") + + def read_images(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "images") + + def read_pivot_tables(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "pivot_tables") + + def read_comments(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "comments") + + def read_freeze_panes(self, workbook: ModelWorkbook, sheet: str) -> JSONDict: + self._require_read(workbook, "freeze_panes") + return dict(self._sheet(workbook, sheet).get("freeze_panes") or {}) + + def read_named_ranges(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + self._require_read(workbook, "named_ranges") + out: list[JSONDict] = [] + for item in workbook.model.get("named_ranges", []): + scope = item.get("scope") or "workbook" + if scope == "sheet" and item.get("sheet") != sheet: + continue + out.append( + { + "name": str(item.get("name")), + "scope": scope, + "refers_to": _normalize_refers_to(item.get("refers_to")), + } + ) + return out + + def read_tables(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "tables") + + def read_sheet_protection(self, workbook: ModelWorkbook, sheet: str) -> JSONDict: + self._require_read(workbook, "sheet_protection") + return dict(self._sheet(workbook, sheet).get("sheet_protection") or {}) + + def read_page_setup(self, workbook: ModelWorkbook, sheet: str) -> JSONDict: + self._require_read(workbook, "page_setup") + return dict(self._sheet(workbook, sheet).get("page_setup") or {}) + + def read_chart_anchors(self, workbook: ModelWorkbook, sheet: str) -> list[JSONDict]: + return self._sheet_list(workbook, sheet, "chart_anchors") + + # ========================================================================= + # Write side + # ========================================================================= + + def _record(self, workbook: OpLog, op: str, **fields: Any) -> None: + reason = self.describe().get("unsupported_write", {}).get(op) + if reason: + self.unsupported_operation(op, str(reason)) + workbook.ops.append({"op": op, **_json_safe(fields)}) + + def create_workbook(self) -> OpLog: + return OpLog() + + def add_sheet(self, workbook: OpLog, name: str) -> None: + self._record(workbook, "add_sheet", name=name) + + def write_cell_value( + self, workbook: OpLog, sheet: str, cell: str, value: CellValue + ) -> None: + self._record( + workbook, + "cell_value", + sheet=sheet, + cell=cell, + type=value.type.value, + value=value.value, + formula=value.formula, + ) + + def write_cell_format( + self, workbook: OpLog, sheet: str, cell: str, format: CellFormat + ) -> None: + fmt = {key: getattr(format, key) for key in _FORMAT_FIELDS} + self._record( + workbook, + "cell_format", + sheet=sheet, + cell=cell, + format={k: v for k, v in fmt.items() if v is not None}, + ) + + def write_cell_border( + self, workbook: OpLog, sheet: str, cell: str, border: BorderInfo + ) -> None: + edges: JSONDict = {} + for edge_name in _BORDER_EDGES: + edge = getattr(border, edge_name) + if edge is not None and edge.style != BorderStyle.NONE: + edges[edge_name] = {"style": edge.style.value, "color": edge.color} + self._record(workbook, "cell_border", sheet=sheet, cell=cell, border=edges) + + def set_row_height( + self, workbook: OpLog, sheet: str, row: int, height: float + ) -> None: + self._record(workbook, "row_height", sheet=sheet, row=row, height=height) + + def set_column_width( + self, workbook: OpLog, sheet: str, column: str, width: float + ) -> None: + self._record(workbook, "column_width", sheet=sheet, column=column, width=width) + + def merge_cells(self, workbook: OpLog, sheet: str, cell_range: str) -> None: + self._record(workbook, "merge", sheet=sheet, range=cell_range) + + def add_conditional_format( + self, workbook: OpLog, sheet: str, rule: JSONDict + ) -> None: + self._record( + workbook, "conditional_format", sheet=sheet, rule=rule.get("cf_rule", rule) + ) + + def add_data_validation( + self, workbook: OpLog, sheet: str, validation: JSONDict + ) -> None: + self._record( + workbook, + "data_validation", + sheet=sheet, + validation=validation.get("validation", validation), + ) + + def add_hyperlink(self, workbook: OpLog, sheet: str, link: JSONDict) -> None: + self._record( + workbook, "hyperlink", sheet=sheet, link=link.get("hyperlink", link) + ) + + def add_image(self, workbook: OpLog, sheet: str, image: JSONDict) -> None: + data = dict(image.get("image", image)) + if data.get("path"): + data["path"] = str(Path(str(data["path"])).resolve()) + self._record(workbook, "image", sheet=sheet, image=data) + + def add_pivot_table(self, workbook: OpLog, sheet: str, pivot: JSONDict) -> None: + self._record(workbook, "pivot", sheet=sheet, pivot=pivot.get("pivot", pivot)) + + def add_comment(self, workbook: OpLog, sheet: str, comment: JSONDict) -> None: + self._record( + workbook, "comment", sheet=sheet, comment=comment.get("comment", comment) + ) + + def set_freeze_panes(self, workbook: OpLog, sheet: str, settings: JSONDict) -> None: + self._record( + workbook, "freeze", sheet=sheet, settings=settings.get("freeze", settings) + ) + + def add_named_range( + self, workbook: OpLog, sheet: str, named_range: JSONDict + ) -> None: + self._record( + workbook, + "named_range", + sheet=sheet, + named_range=named_range.get("named_range", named_range), + ) + + def add_table(self, workbook: OpLog, sheet: str, table: JSONDict) -> None: + self._record(workbook, "table", sheet=sheet, table=table.get("table", table)) + + def set_sheet_protection( + self, workbook: OpLog, sheet: str, settings: JSONDict + ) -> None: + self._record( + workbook, + "protection", + sheet=sheet, + settings=settings.get("protection", settings), + ) + + def set_page_setup(self, workbook: OpLog, sheet: str, settings: JSONDict) -> None: + self._record( + workbook, + "page_setup", + sheet=sheet, + settings=settings.get("page_setup", settings), + ) + + def add_chart_with_anchor( + self, workbook: OpLog, sheet: str, chart: JSONDict + ) -> None: + self._record(workbook, "chart", sheet=sheet, chart=chart.get("chart", chart)) + + def save_workbook(self, workbook: OpLog, path: Path) -> None: + output = Path(path).resolve() + output.parent.mkdir(parents=True, exist_ok=True) + self.call_helper( + "write_model", payload={"ops": workbook.ops}, output_path=output + ) + if not output.is_file(): + raise HelperError( + f"{self.name} write_model reported success but wrote no file" + ) + + # ========================================================================= + # Modify side (template-mutation lane) + # ========================================================================= + + @classmethod + def mutate_file( + cls, template: Path, output: Path, mutations: list[JSONDict] + ) -> None: + """Open ``template`` with the library, set cell values, save to ``output``.""" + output = Path(output).resolve() + output.parent.mkdir(parents=True, exist_ok=True) + cls.call_helper( + "mutate", + payload={"mutations": json.loads(json.dumps(_json_safe(mutations)))}, + input_path=Path(template).resolve(), + output_path=output, + ) + if not output.is_file(): + raise HelperError( + f"{cls.__name__} mutate reported success but wrote no file" + ) diff --git a/src/excelbench/harness/adapters/libreoffice_adapter.py b/src/excelbench/harness/adapters/libreoffice_adapter.py new file mode 100644 index 0000000..2c8860d --- /dev/null +++ b/src/excelbench/harness/adapters/libreoffice_adapter.py @@ -0,0 +1,55 @@ +"""Adapter for LibreOffice Calc driven headlessly through its UNO API. + +The helper runs a Python macro inside ``soffice --headless`` (LibreOffice's +own embedded Python), so every read and write goes through Calc's import and +export filters exactly as a server-side LibreOffice conversion would. +""" + +from __future__ import annotations + +import os +import shutil +import sys +from pathlib import Path + +from excelbench.harness.adapters.json_model_adapter import JsonModelAdapter +from excelbench.harness.external_oracles import ExternalOracleTool + +_HELPER_DIR = Path(__file__).resolve().parents[4] / "tools" / "external-oracles" / "libreoffice" + + +def soffice_binary() -> str | None: + """Resolve the soffice executable the helper will launch.""" + for candidate in ( + os.environ.get("LIBREOFFICE_BIN"), + shutil.which("soffice"), + shutil.which("libreoffice"), + "/Applications/LibreOffice.app/Contents/MacOS/soffice", + ): + if candidate and Path(candidate).exists(): + return candidate + return None + + +class LibreofficeAdapter(JsonModelAdapter): + """LibreOffice Calc read/write/modify via headless UNO.""" + + LIBRARY_NAME = "libreoffice" + LANGUAGE = "cli" + TIMEOUT_SECONDS = 180.0 + + @classmethod + def tool(cls) -> ExternalOracleTool: + return ExternalOracleTool( + name="libreoffice-uno", + command=(sys.executable, str(_HELPER_DIR / "libreoffice_uno_adapter.py")), + language="cli", + homepage="https://www.libreoffice.org/", + capabilities=frozenset({"read", "write", "modify"}), + cwd=_HELPER_DIR, + required_paths=(_HELPER_DIR / "uno" / "excelbench_uno.py",), + ) + + @classmethod + def is_available(cls) -> bool: + return super().is_available() and soffice_binary() is not None diff --git a/src/excelbench/harness/adapters/openpyxl_adapter.py b/src/excelbench/harness/adapters/openpyxl_adapter.py index e5870f7..dfb4cc2 100644 --- a/src/excelbench/harness/adapters/openpyxl_adapter.py +++ b/src/excelbench/harness/adapters/openpyxl_adapter.py @@ -1262,7 +1262,7 @@ 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), + "password_hash_present": bool(prot.password or prot.hashValue), "format_cells": prot.formatCells, "insert_rows": prot.insertRows, "select_locked_cells": prot.selectLockedCells, diff --git a/src/excelbench/harness/adapters/sheetjs_adapter.py b/src/excelbench/harness/adapters/sheetjs_adapter.py new file mode 100644 index 0000000..fa76def --- /dev/null +++ b/src/excelbench/harness/adapters/sheetjs_adapter.py @@ -0,0 +1,32 @@ +"""Adapter for SheetJS Community Edition (npm ``xlsx``) via a Node helper.""" + +from __future__ import annotations + +from pathlib import Path + +from excelbench.harness.adapters.json_model_adapter import JsonModelAdapter +from excelbench.harness.external_oracles import ExternalOracleTool + +_HELPER_DIR = Path(__file__).resolve().parents[4] / "tools" / "external-oracles" / "sheetjs" + + +class SheetjsAdapter(JsonModelAdapter): + """SheetJS CE read/write; modify means read the package, then write it back.""" + + LIBRARY_NAME = "sheetjs" + LANGUAGE = "javascript" + + @classmethod + def tool(cls) -> ExternalOracleTool: + return ExternalOracleTool( + name="sheetjs", + command=("node", str(_HELPER_DIR / "sheetjs-adapter.cjs")), + language="node", + homepage="https://docs.sheetjs.com/", + capabilities=frozenset({"read", "write", "modify"}), + cwd=_HELPER_DIR, + required_paths=( + _HELPER_DIR / "sheetjs-adapter.cjs", + _HELPER_DIR / "node_modules" / "xlsx" / "package.json", + ), + ) diff --git a/src/excelbench/harness/content_model_xlsx.py b/src/excelbench/harness/content_model_xlsx.py new file mode 100644 index 0000000..71ef33e --- /dev/null +++ b/src/excelbench/harness/content_model_xlsx.py @@ -0,0 +1,2595 @@ +# Vendored verbatim from officelibs-corpus/src/officecorpus/model/xlsx.py +# sha256 17fb55bc132caf91a23f07e1df35423dda7f5e14051837f88dd708ccf7b19e61 +# Do not edit here; update the source repo and re-vendor. +"""Spreadsheet (xlsx) content model: what a user of the workbook can observe. + +`extract(path)` reads an OOXML spreadsheet package and returns a deterministic, +JSON-serializable model whose top-level keys are `FEATURES`. `compare(before, +after)` lists the differences between two models; an empty list means the +content was preserved. The model never records how a writer serialized the +content (part names, relationship ids, attribute order, shared vs inline +strings, style table layout, default values spelled out or omitted), so a +library that rewrites a workbook into an equivalent form scores exactly the +same as one that copies bytes. + +Shared cross-format rule (identical in the xlsx, docx and pptx models) +- Presentation-only lengths compare equal when they differ by at most 0.5 pt. + Color modifiers (tint, shade, lumMod-like values on a 0..1 or -1..1 scale) + compare by rendered effect: equal when they differ by at most 1/510, so + they cannot change an 8-bit channel by a full level. Other + presentation-only floats that are not lengths (shading percentages, + gradient geometry, scale factors) compare equal within a relative 1e-9. + Everything else, including cell values, formula text, number formats, font + sizes and every non-presentation number, compares exactly: data is data. +- xlsx lengths: column widths are in characters of the workbook default + font, converted at 1 character = 7 px = 5.25 pt (tolerance 0.5 / 5.25 = + 0.095 characters); row heights (including the default row height) are in + points (0.5); page margins and header/footer margins are in inches + (0.5 / 72). Drawing anchor offsets are not part of the model (images and + charts are anchored by cell), so the 6350 EMU tolerance has nothing to + apply to. +- xlsx color modifiers: the `~tint:` of any color (an absent tint is 0, so + `theme:1` equals `theme:1~tint:0.001`). xlsx relative floats: gradient + fill parameters (degree, left/right/top/bottom, stop positions). +- Content-addressed entries (conditional formats, data validations) whose + values are equal under these tolerances count as the same entry even + though their exact hashes differ. +- Equivalent spellings compare equal because the model stores one canonical + form. xlsx: SpreadsheetML style colors (fonts, fills, borders, dxf, + conditional-format colors, color scales, data bars, tab colors, rich-text + runs, indexed palette, theme scheme colors) are 6-digit uppercase RGB, + because Excel ignores the alpha byte (`001F4E78` == `FF1F4E78` == + `1f4e78`); an indexed color equals the explicit RGB its palette entry + holds; `auto`, indexed 64 and an absent color are all automatic; a tint of + 0 equals no tint. The model records no DrawingML colors, where alpha + (a:alpha and other srgbClr modifiers) is real and would be kept. + +Package rules +- Parts are matched case-insensitively with percent-decoding. Relationships are + followed by type (the last path segment of the relationship type URI, so + transitional and strict URIs agree) and resolved target. A relationship id is + only used to dereference an `r:id` attribute inside the part that owns it; + no rId value ever enters the model. +- Element and attribute names are compared by local name, so transitional and + strict namespaces produce the same model. +- A file that is not a zip archive, has no workbook part, or contains XML that + cannot be parsed raises `ValueError`. Relationships whose target part is + absent are ignored (nothing observable is behind them). + +Equivalence rules +- Absent == default. Every attribute with a documented default is either + filled with it or dropped when equal to it, so writing a default explicitly + never differs from omitting it. +- Dicts are keyed (set or map semantics, order ignored); lists are ordered and + used only where order is user-visible (sheet order, rich-text runs, chart + plots and series, table columns, comment threads, gradient stops, print + areas, conditional-format formulas). +- Numbers are parsed to float and compared exactly, except for the + presentation tolerances in the shared rule above. +- Colors: rgb as uppercase 6-digit RGB (the alpha byte of an 8-digit ARGB is + dropped, see equivalent spellings), theme colors stay symbolic + (`theme:N`), indexed colors resolve to RGB + through the workbook's palette (custom indexedColors entries override the + ECMA default palette by index; out-of-range indexes stay + `indexed:N`; 65 is `system-background`), a non-zero tint is appended as + `~tint:`, and `auto`, indexed 64 (system foreground) and absent all + mean automatic (None). Referenced theme colors are modeled under `theme` + so symbolic colors stay comparable. +- Strings decode the OOXML `_xHHHH_` escape. Phonetic runs (`rPh`) are not + text. +- Formulas: leading/trailing whitespace and one leading `=` are removed, + everything outside string literals is upper-cased (Excel formulas are + case-insensitive outside literals), unquoted sheet prefixes are quoted + (`Sheet1!A1` == `'Sheet1'!A1`), and whitespace outside literals is dropped + unless it separates two operands (the intersection operator), where it + becomes one space. String literals and structured-reference brackets are + kept verbatim apart from upper-casing the brackets. Shared formulas are + expanded per cell by shifting the anchor formula's relative A1 references, + so a writer that de-shares formulas compares equal. +- Ranges: `$` dropped, upper-cased, corners ordered, a one-cell range is the + cell, a full-height range is a column range (`A:A`), a full-width range is a + row range (`1:1`). Multi-area sqrefs (data validations, conditional + formats) are canonicalized as the cell-set union decomposed into maximal + row bands, so any split/merge/reorder of the same cells compares equal. + +Feature rules +- workbook: sheet order (list of names), per sheet kind (worksheet, + chartsheet, dialogsheet, macrosheet, or `missing` if the part is absent) + and visibility (`visible` default), `date1904`. +- defined_names: keyed `!` (scope is the sheet name for + sheet-local names, empty for workbook names) -> normalized refers-to plus + `hidden` when true. `_xlnm._FilterDatabase` is excluded (derived from the + auto filter, modeled under auto_filters); `_xlnm.Print_Titles` and + `_xlnm.Print_Area` are modeled under page_setup; other built-in names stay. +- cells: per sheet, address -> `{"type", "value"}` with type `n` (float), `s` + (shared, inline and formula-string results all resolve to plain text), `b` + (bool), `e` (error text). `t="d"` ISO dates become the numeric serial for the + workbook's date system (1900 system keeps Excel's 1900-02-29 slot). Rich text + adds `runs`: `[{"text", "font"}]` where each run's font is the cell font + overridden by the run properties, adjacent runs with equal fonts merged; runs + are dropped when every run renders in the cell font. Formula cells carry + their cached result here (missing cached value == no cell entry); unparsable + values are recorded as type `invalid`. +- formulas: per sheet, address -> `{"text"}` plus `array` (canonical ref) for + array/dynamic-array anchors, or `data_table` (its attributes) for what-if + tables. +- cell_styles: `default` is the resolved style of cellXfs[0]. Per sheet, + address -> resolved style for every cell whose style differs from the style + an absent cell would have there (the row style if the row has + customFormat, else the column style, else the default). A style is + `number_format` (format code; ECMA built-in ids and Excel's en-US codes + for 41-44 mapped to their codes, other + built-in ids kept as `builtin:N`; a backslash escape of a character that + displays literally anyway, such as `\\-`, is dropped), `font` (name, size, + bold, italic, underline, strike, color, vert_align), `fill` (pattern none + drops colors, solid keeps only fg; gradients keep type, degree, edges, + stops), `border` + (left/right/top/bottom, style none drops color, `start`/`end` == left/right, + diagonal only when diagonalUp/Down), `alignment` and `protection`, all with + defaults filled. cellXfs values are used as-is (apply* flags ignored); + font family/charset/scheme are not modeled. Merged areas: the anchor + cell holds what the area renders, the anchor style with its border + replaced by the per-cell perimeter sides (top of the top row, bottom of + the bottom row, left/right of the outer columns; a uniform side collapses + to one value); styles of covered cells and interior borders are not + rendered and are dropped (covered cell values stay under cells). In the + model, styles are content-addressed keys into `cell_styles.table`; + `compare` expands them so differences are reported per style field and + the table itself is never compared. +- merged_cells: per sheet, set of canonical ranges. +- columns: per sheet, maximal runs of adjacent columns with identical + non-default properties (`width` when given, `hidden`, `outline_level`, + `collapsed`, `style` when not the default), keyed `A:C`. `compare` + re-keys both sides onto their common run boundaries first, so runs that + split differently are compared column range by column range. +- rows: per sheet, row number -> non-default properties: `height` only when + customHeight (a non-custom `ht` is an autofit result the application + recomputes, so it is not compared), `hidden`, `outline_level`, `collapsed`, + `style` when + customFormat and not the default. Plus `_default` for a custom default row + height / zeroHeight from sheetFormatPr. +- views: per sheet, first sheet view: frozen pane (`freeze` cols/rows from + xSplit/ySplit when the pane state is frozen/frozenSplit), right_to_left, + show_gridlines, show_headers, zoom, tab_color. +- auto_filters: per sheet, `ref` and filter column criteria (canonical dump + keyed by column id). +- data_validations: per sheet, validations grouped by their parameters (type + default `none`, operator default `between`, formulas, allow_blank, + show_dropdown, input/error message flags, texts, error style) with the + union of their sqrefs. Main and x14 extension validations are one set. +- conditional_formats: per sheet, set of rules (sqref, type, operator, + formulas, priority rank within the sheet, differential style, stop_if_true, + type-specific attributes with defaults dropped, color scale / data bar / + icon set parameters, and linked x14 extension parameters). Priorities are + replaced by their rank so renumbering is invisible. Only what the rule + type reads is kept: operator for cellIs and the text rules, text for the + text rules, timePeriod, rank/percent/bottom for top10, + aboveAverage/equalAverage/stdDev for aboveAverage; formulas are dropped + for aboveAverage, top10, duplicate/unique values, color scales, data bars + and icon sets; cfvo `val` is dropped for min/max thresholds. Unlinked x14 + rules are too. Differential styles keep only what they set: a dxf fill + without patternType is solid and its color is bgColor (else fgColor), a + dxf border side without a style sets nothing, a dxf diagonal counts only + with diagonalUp/Down. Parameter dumps (and auto filter criteria) map + boolean `true`/`false` to `1`/`0` and drop documented defaults (data bar + lengths, direction, axis, gradient, border, negative-bar flags; icon set + name, custom, showValue, percent, reverse; cfvo gte). +- hyperlinks: per sheet, canonical ref -> external `target` and/or in-workbook + `location` and `tooltip`. +- comments: per sheet, `notes` (address -> author, text) and `threads` + (address -> ordered list of author display name, text). A legacy note on + a cell that has a thread is the thread's compatibility shadow and is + dropped. +- protection: workbook lock_structure/lock_windows; per sheet the + sheetProtection `sheet` flag (chartsheets: `content`). +- page_setup: per worksheet orientation (`default` == portrait), paper_size, + fit_to_page with fit_width/fit_height (or scale when not fitting), margins + with Excel defaults, header/footer texts (`_xHHHH_` decoded, split into + left/center/right sections by &L/&C/&R; text before any section code is + center; empty sections dropped) and flags, print_titles + (`rows`/`cols`), print_area (ordered list of canonical refs). +- images: per sheet, multiset `|` -> count, + anchor being the from-cell of drawing anchors, `absolute`, or `background` + for the sheet background picture. AlternateContent uses its first Choice. +- charts: per sheet, keyed by anchor (`#n` suffix for duplicates; chartsheets + use `sheet`): plot types (bar charts carry their direction), title + (`text`, `ref`, or `auto` when a title element has no text, which Excel + fills automatically), series (name, values, categories, x/y, bubble sizes; + references normalized and `$`-free) ordered by series order. ChartEx + charts record their series layout ids. +- tables: per sheet, display name -> ref, columns, header/totals flags, + style name and stripe flags. +- pivot_tables: per sheet, name -> location and cache source. +- external_links: number of external workbook links. +- vba: presence of a VBA project part. +- theme: `colors`: theme color index -> scheme color (`sysClr` resolves to + its lastClr RGB; indexes 0-3 map to lt1, dk1, lt2, dk2) for the theme + indexes the model actually references. Unreferenced theme colors and theme + fonts are not observable through modeled content. + +Not modeled: VML shapes, form controls, header/footer images, slicers, +sparklines, chart formatting beyond types/series/title, calculation chain, +document properties, workbook views, and the default column width (it +depends on font metrics). +""" + +from __future__ import annotations + +import contextvars +import datetime as _dt +import functools +import hashlib +import itertools +import json +import posixpath +import re +import xml.etree.ElementTree as ET +import zipfile +from pathlib import Path +from typing import Any +from urllib.parse import unquote + +FEATURES: tuple[str, ...] = ( + "workbook", + "defined_names", + "cells", + "formulas", + "cell_styles", + "merged_cells", + "columns", + "rows", + "views", + "auto_filters", + "data_validations", + "conditional_formats", + "hyperlinks", + "comments", + "protection", + "page_setup", + "images", + "charts", + "tables", + "pivot_tables", + "external_links", + "vba", + "theme", +) + +MAX_ROW = 1048576 +MAX_COL = 16384 + +# --------------------------------------------------------------------------- +# XML / package helpers +# --------------------------------------------------------------------------- + + +def _ln(tag: Any) -> str: + return tag.rsplit("}", 1)[-1] if isinstance(tag, str) else "" + + +def _kids(el: Any, name: str) -> list[Any]: + return [c for c in el if _ln(c.tag) == name] if el is not None else [] + + +def _kid(el: Any, name: str) -> Any: + if el is None: + return None + for c in el: + if _ln(c.tag) == name: + return c + return None + + +def _attr(el: Any, local: str) -> str | None: + """Attribute by local name (any namespace, unqualified first).""" + if el is None: + return None + value = el.get(local) + if value is not None: + return value + for key, val in el.attrib.items(): + if key.startswith("{") and _ln(key) == local: + return val + return None + + +def _rel_attr(el: Any, local: str) -> str | None: + """A relationship-namespace attribute such as r:id or r:embed.""" + for key, val in el.attrib.items(): + if key.startswith("{") and _ln(key) == local: + ns = key[1:].split("}", 1)[0] + if ns.endswith("relationships"): + return val + return None + + +def _bool(value: str | None, default: bool) -> bool: + if value is None: + return default + v = value.strip().lower() + if v in ("1", "true", "on"): + return True + if v in ("0", "false", "off"): + return False + return default + + +def _float(value: str | None, default: float | None = None) -> float | None: + if value is None: + return default + try: + return float(value) + except ValueError: + return default + + +def _int(value: str | None, default: int | None = None) -> int | None: + if value is None: + return default + try: + return int(float(value)) + except ValueError: + return default + + +_ESCAPE_RE = re.compile(r"_x([0-9A-Fa-f]{4})_") + + +def _unescape(text: str) -> str: + return _ESCAPE_RE.sub(lambda m: chr(int(m.group(1), 16)), text) + + +def _hf_sections(text: str) -> dict[str, str]: + """Split header/footer text into its &L/&C/&R sections (default: center).""" + sections = {"left": "", "center": "", "right": ""} + current = "center" + i = 0 + while i < len(text): + if text[i] == "&" and i + 1 < len(text) and text[i + 1] in "LCR": + current = {"L": "left", "C": "center", "R": "right"}[text[i + 1]] + i += 2 + continue + step = 2 if text[i] == "&" and i + 1 < len(text) else 1 + sections[current] += text[i : i + step] + i += step + return {k: v for k, v in sections.items() if v} + + +def _text_of(el: Any) -> str: + """Plain text of a string item / comment text: t + r/t, skipping rPh.""" + if el is None: + return "" + parts: list[str] = [] + for c in el: + name = _ln(c.tag) + if name == "t": + parts.append(c.text or "") + elif name == "r": + t = _kid(c, "t") + parts.append((t.text or "") if t is not None else "") + if not parts and _ln(el.tag) == "t": + parts.append(el.text or "") + return _unescape("".join(parts)) + + +def _key(value: Any) -> str: + raw = json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + return hashlib.sha256(raw.encode()).hexdigest()[:16] + + +class _Rel: + __slots__ = ("external", "kind", "target") + + def __init__(self, kind: str, target: str, external: bool) -> None: + self.kind = kind + self.target = target + self.external = external + + +class _Package: + def __init__(self, path: Path) -> None: + try: + archive = zipfile.ZipFile(path) + except (zipfile.BadZipFile, OSError, ValueError) as exc: + raise ValueError(f"not a zip archive: {exc}") from exc + self.parts: dict[str, bytes] = {} + with archive: + for info in archive.infolist(): + if info.is_dir(): + continue + key = unquote(info.filename.lstrip("/")).lower() + if key in self.parts: + raise ValueError(f"duplicate part name: {info.filename}") + try: + self.parts[key] = archive.read(info) + except Exception as exc: # zlib, CRC, encryption + raise ValueError( + f"unreadable zip member {info.filename}: {exc}" + ) from exc + self._xml: dict[str, Any] = {} + self._rels: dict[str, dict[str, _Rel]] = {} + + def xml(self, key: str) -> Any: + if key not in self._xml: + try: + self._xml[key] = ET.fromstring(self.parts[key]) + except ET.ParseError as exc: + raise ValueError(f"malformed XML in {key}: {exc}") from exc + return self._xml[key] + + def rels(self, source: str) -> dict[str, _Rel]: + """Relationship id -> relationship, for dereferencing r:id in `source`.""" + if source in self._rels: + return self._rels[source] + if source == "": + rels_key = "_rels/.rels" + else: + directory, base = posixpath.split(source) + rels_key = posixpath.join(directory, "_rels", base + ".rels") + out: dict[str, _Rel] = {} + if rels_key in self.parts: + for child in self.xml(rels_key): + if _ln(child.tag) != "Relationship": + continue + kind = child.get("Type", "").rstrip("/").rsplit("/", 1)[-1] + target = child.get("Target", "") + external = child.get("TargetMode", "Internal") == "External" + if not external: + target = unquote(target.split("#", 1)[0]) + if target.startswith("/"): + target = target.lstrip("/") + else: + target = posixpath.normpath( + posixpath.join(posixpath.dirname(source), target) + ) + target = target.lower() + out[child.get("Id", "")] = _Rel(kind, target, external) + self._rels[source] = out + return out + + def targets(self, source: str, kind: str) -> list[str]: + """Existing internal parts reached from `source` by relationship type.""" + return sorted( + r.target + for r in self.rels(source).values() + if r.kind == kind and not r.external and r.target in self.parts + ) + + def deref(self, source: str, rid: str | None) -> _Rel | None: + if not rid: + return None + return self.rels(source).get(rid) + + +# --------------------------------------------------------------------------- +# Cell references and ranges +# --------------------------------------------------------------------------- + +_CELL_RE = re.compile(r"^\$?([A-Za-z]{1,3})\$?([0-9]+)$") +_COLS_RE = re.compile(r"^\$?([A-Za-z]{1,3}):\$?([A-Za-z]{1,3})$") +_ROWS_RE = re.compile(r"^\$?([0-9]+):\$?([0-9]+)$") + + +@functools.cache +def _col_num(letters: str) -> int: + n = 0 + for ch in letters.upper(): + n = n * 26 + ord(ch) - 64 + return n + + +@functools.cache +def _col_name(n: int) -> str: + out = "" + while n > 0: + n, rem = divmod(n - 1, 26) + out = chr(65 + rem) + out + return out + + +def _parse_cell(text: str) -> tuple[int, int] | None: + m = _CELL_RE.match(text.strip()) + if not m: + return None + return int(m.group(2)), _col_num(m.group(1)) + + +def _parse_range(text: str) -> tuple[int, int, int, int] | None: + """(r1, c1, r2, c2) for A1, A1:B2, A:B, 1:2; None if not a plain range.""" + text = text.strip() + if ":" in text: + a, _, b = text.partition(":") + pa, pb = _parse_cell(a), _parse_cell(b) + if pa and pb: + r1, r2 = sorted((pa[0], pb[0])) + c1, c2 = sorted((pa[1], pb[1])) + return r1, c1, r2, c2 + m = _COLS_RE.match(text) + if m: + c1, c2 = sorted((_col_num(m.group(1)), _col_num(m.group(2)))) + return 1, c1, MAX_ROW, c2 + m = _ROWS_RE.match(text) + if m: + r1, r2 = sorted((int(m.group(1)), int(m.group(2)))) + return r1, 1, r2, MAX_COL + return None + p = _parse_cell(text) + return (p[0], p[1], p[0], p[1]) if p else None + + +def _render_range(r1: int, c1: int, r2: int, c2: int) -> str: + if r1 == 1 and r2 == MAX_ROW: + return f"{_col_name(c1)}:{_col_name(c2)}" + if c1 == 1 and c2 == MAX_COL: + return f"{r1}:{r2}" + if r1 == r2 and c1 == c2: + return f"{_col_name(c1)}{r1}" + return f"{_col_name(c1)}{r1}:{_col_name(c2)}{r2}" + + +def _canon_ref(text: str | None) -> str | None: + if text is None: + return None + rect = _parse_range(text) + return _render_range(*rect) if rect else text.replace("$", "").strip().upper() + + +def _canon_sqref(text: str | None) -> str: + """Canonical cell-set union of a space-separated multi-area reference.""" + rects: list[tuple[int, int, int, int]] = [] + other: list[str] = [] + for token in (text or "").split(): + rect = _parse_range(token) + if rect: + rects.append(rect) + else: + other.append(token.replace("$", "").upper()) + if not rects: + return " ".join(sorted(set(other))) + edges = sorted({r[0] for r in rects} | {r[2] + 1 for r in rects}) + bands: list[list[Any]] = [] + for lo, hi in itertools.pairwise(edges): + spans = sorted( + (c1, c2) for r1, c1, r2, c2 in rects if r1 <= lo and r2 >= hi - 1 + ) + merged: list[list[int]] = [] + for c1, c2 in spans: + if merged and c1 <= merged[-1][1] + 1: + merged[-1][1] = max(merged[-1][1], c2) + else: + merged.append([c1, c2]) + cols = tuple(tuple(m) for m in merged) + if not cols: + continue + if bands and bands[-1][1] == lo - 1 and bands[-1][2] == cols: + bands[-1][1] = hi - 1 + else: + bands.append([lo, hi - 1, cols]) + out = sorted((r1, c1, r2, c2) for r1, r2, cols in bands for c1, c2 in cols) + return " ".join([_render_range(*r) for r in out] + sorted(set(other))) + + +# --------------------------------------------------------------------------- +# Formulas +# --------------------------------------------------------------------------- + +_ERROR_RE = re.compile( + r"#(?:NULL!|DIV/0!|VALUE!|REF!|NAME\?|NUM!|N/A|GETTING_DATA|SPILL!|CALC!" + r"|FIELD!|BLOCKED!|UNKNOWN!|CONNECT!|BUSY!|PYTHON!|EXTERNAL!)", + re.IGNORECASE, +) + + +def _skip_quoted(text: str, i: int, quote: str) -> int: + j = i + 1 + n = len(text) + while j < n: + if text[j] == quote: + if j + 1 < n and text[j + 1] == quote: + j += 2 + continue + return j + 1 + j += 1 + return n + + +def _skip_brackets(text: str, i: int) -> int: + depth = 0 + j = i + n = len(text) + while j < n: + ch = text[j] + if ch == "'": + j += 2 + continue + if ch == "[": + depth += 1 + elif ch == "]": + depth -= 1 + if depth == 0: + return j + 1 + j += 1 + return n + + +def _operand_end(ch: str) -> bool: + return ch.isalnum() or ch in "_$.)'\"]?\\%" or ord(ch) > 127 + + +def _operand_start(ch: str) -> bool: + return ch.isalnum() or ch in "_$.('\"[#\\" or ord(ch) > 127 + + +def _sheet_char(ch: str) -> bool: + return ch.isalnum() or ch in "_.\\[]:" or ord(ch) > 127 + + +def _normalize_formula(text: str | None) -> str | None: + if text is None: + return None + s = text.strip() + if s.startswith("="): + s = s[1:].lstrip() + out: list[str] = [] + pending_space = False + i = 0 + n = len(s) + + def emit(token: str) -> None: + nonlocal pending_space + if pending_space and out and token: + prev = out[-1][-1] if out[-1] else "" + if prev and _operand_end(prev) and _operand_start(token[0]): + out.append(" ") + pending_space = False + out.append(token) + + while i < n: + ch = s[i] + if ch == '"': + j = _skip_quoted(s, i, '"') + emit(s[i:j]) + i = j + elif ch == "'": + j = _skip_quoted(s, i, "'") + emit(s[i:j].upper()) + i = j + elif ch == "[": + j = _skip_brackets(s, i) + emit(s[i:j].upper()) + i = j + elif ch.isspace(): + while i < n and s[i].isspace(): + i += 1 + pending_space = True + elif ch == "#" and _ERROR_RE.match(s, i): + m = _ERROR_RE.match(s, i) + emit(m.group(0).upper()) + i = m.end() + elif ch == "!": + pending_space = False + joined = "".join(out) + if joined and not joined.endswith("'"): + j = len(joined) + while j > 0 and _sheet_char(joined[j - 1]): + j -= 1 + if j < len(joined) and not (j > 0 and joined[j - 1] == "#"): + joined = joined[:j] + "'" + joined[j:] + "'" + out[:] = [joined, "!"] if joined else ["!"] + i += 1 + else: + emit(ch.upper()) + i += 1 + return "".join(out) + + +_REF_RE = re.compile( + r"(?\$?)(?P[A-Za-z]{1,3})(?P\$?)(?P[0-9]+)" + r"|(?P\$?)(?P[A-Za-z]{1,3}):(?P\$?)(?P[A-Za-z]{1,3})" + r"|(?P\$?)(?P[0-9]+):(?P\$?)(?P[0-9]+)" + r")(?![A-Za-z0-9_(.!\\\[])" +) + + +def _plain_spans(text: str) -> list[tuple[int, int]]: + spans: list[tuple[int, int]] = [] + start = i = 0 + n = len(text) + while i < n: + ch = text[i] + if ch in "\"'": + if start < i: + spans.append((start, i)) + i = _skip_quoted(text, i, ch) + start = i + elif ch == "[": + if start < i: + spans.append((start, i)) + i = _skip_brackets(text, i) + start = i + else: + i += 1 + if start < n: + spans.append((start, n)) + return spans + + +def _translate(text: str, drow: int, dcol: int) -> str: + """Shift relative A1 references by (drow, dcol), as Excel fills a formula.""" + if not drow and not dcol: + return text + spans = _plain_spans(text) + out: list[str] = [] + last = 0 + for m in _REF_RE.finditer(text): + if not any(s <= m.start() and m.end() <= e for s, e in spans): + continue + if m.group("c") is not None: + col, row = _col_num(m.group("c")), int(m.group("r")) + if col > MAX_COL or row > MAX_ROW or row < 1: + continue + if not m.group("cd"): + col += dcol + if not m.group("rd"): + row += drow + if not (1 <= col <= MAX_COL and 1 <= row <= MAX_ROW): + new = "#REF!" + else: + new = f"{m.group('cd')}{_col_name(col)}{m.group('rd')}{row}" + elif m.group("a") is not None: + a, b = _col_num(m.group("a")), _col_num(m.group("b")) + if a > MAX_COL or b > MAX_COL: + continue + if not m.group("ad"): + a += dcol + if not m.group("bd"): + b += dcol + if not (1 <= a <= MAX_COL and 1 <= b <= MAX_COL): + new = "#REF!" + else: + new = f"{m.group('ad')}{_col_name(a)}:{m.group('bd')}{_col_name(b)}" + else: + x, y = int(m.group("x")), int(m.group("y")) + if not m.group("xd"): + x += drow + if not m.group("yd"): + y += drow + if not (1 <= x <= MAX_ROW and 1 <= y <= MAX_ROW): + new = "#REF!" + else: + new = f"{m.group('xd')}{x}:{m.group('yd')}{y}" + out.append(text[last : m.start()]) + out.append(new) + last = m.end() + out.append(text[last:]) + return "".join(out) + + +def _split_areas(text: str) -> list[str]: + """Split a refers-to text on top-level commas (outside quotes/brackets).""" + areas: list[str] = [] + start = i = 0 + depth = 0 + n = len(text) + while i < n: + ch = text[i] + if ch in "\"'": + i = _skip_quoted(text, i, ch) + continue + if ch == "[": + i = _skip_brackets(text, i) + continue + if ch == "(": + depth += 1 + elif ch == ")": + depth -= 1 + elif ch == "," and depth == 0: + areas.append(text[start:i]) + start = i + 1 + i += 1 + areas.append(text[start:]) + return [a.strip() for a in areas if a.strip()] + + +def _strip_sheet(area: str) -> str: + i = 0 + cut = 0 + while i < len(area): + if area[i] == "'": + i = _skip_quoted(area, i, "'") + continue + if area[i] == "!": + cut = i + 1 + i += 1 + return area[cut:] + + +def _chart_ref(text: str | None) -> str | None: + norm = _normalize_formula(text) + return norm.replace("$", "") if norm is not None else None + + +# --------------------------------------------------------------------------- +# Styles +# --------------------------------------------------------------------------- + +_BUILTIN_NUMFMTS = { + 0: "General", + 1: "0", + 2: "0.00", + 3: "#,##0", + 4: "#,##0.00", + 9: "0%", + 10: "0.00%", + 11: "0.00E+00", + 12: "# ?/?", + 13: "# ??/??", + 14: "mm-dd-yy", + 15: "d-mmm-yy", + 16: "d-mmm", + 17: "mmm-yy", + 18: "h:mm AM/PM", + 19: "h:mm:ss AM/PM", + 20: "h:mm", + 21: "h:mm:ss", + 22: "m/d/yy h:mm", + 37: "#,##0 ;(#,##0)", + 38: "#,##0 ;[Red](#,##0)", + 39: "#,##0.00;(#,##0.00)", + 40: "#,##0.00;[Red](#,##0.00)", + # 41-44 are absent from the ECMA table; these are the codes Excel (en-US) + # writes for them. + 41: '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)', + 42: '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)', + 43: '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)', + 44: '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)', + 45: "mm:ss", + 46: "[h]:mm:ss", + 47: "mmss.0", + 48: "##0.0E+0", + 49: "@", +} + +# ECMA-376 Part 1, 18.8.27: the default indexed color palette (indexes 0-63). +_DEFAULT_PALETTE = tuple( + ( + "000000 FFFFFF FF0000 00FF00 0000FF FFFF00 FF00FF 00FFFF " + "000000 FFFFFF FF0000 00FF00 0000FF FFFF00 FF00FF 00FFFF " + "800000 008000 000080 808000 800080 008080 C0C0C0 808080 " + "9999FF 993366 FFFFCC CCFFFF 660066 FF8080 0066CC CCCCFF " + "000080 FF00FF FFFF00 00FFFF 800080 800000 008080 0000FF " + "00CCFF CCFFFF CCFFCC FFFF99 99CCFF FF99CC CC99FF FFCC99 " + "3366FF 33CCCC 99CC00 FFCC00 FF9900 FF6600 666699 969696 " + "003366 339966 003300 333300 993300 993366 333399 333333" + ).split() +) + +_FONT_DEFAULTS = { + "name": None, + "size": None, + "bold": False, + "italic": False, + "underline": "none", + "strike": False, + "color": None, + "vert_align": "baseline", +} +_ALIGN_ATTRS = { + "horizontal": ("horizontal", "general", str), + "vertical": ("vertical", "bottom", str), + "wrapText": ("wrap_text", False, bool), + "shrinkToFit": ("shrink_to_fit", False, bool), + "indent": ("indent", 0, int), + "textRotation": ("text_rotation", 0, int), + "readingOrder": ("reading_order", 0, int), + "justifyLastLine": ("justify_last_line", False, bool), +} +_SIDES = ("left", "right", "top", "bottom") + + +_PALETTE: contextvars.ContextVar[tuple[str, ...]] = contextvars.ContextVar( + "_PALETTE", default=_DEFAULT_PALETTE +) + + +def _color(el: Any) -> str | None: + if el is None or _bool(el.get("auto"), False): + return None + rgb, theme, indexed = el.get("rgb"), el.get("theme"), el.get("indexed") + if rgb: + # SpreadsheetML ignores the alpha byte of ARGB colors when rendering. + value = rgb.strip().upper() + if len(value) == 8: + value = value[2:] + elif theme is not None: + value = f"theme:{_int(theme)}" + elif indexed is not None: + index = _int(indexed) + if index == 64: + return None # system foreground == automatic + if index == 65: + value = "system-background" + else: + palette = _PALETTE.get() + value = ( + palette[index] + if index is not None and 0 <= index < len(palette) + else f"indexed:{indexed}" + ) + else: + return None + tint = _float(el.get("tint"), 0.0) + if tint: + value += f"~tint:{tint!r}" + return value + + +def _font(el: Any, full: bool) -> dict[str, Any]: + d: dict[str, Any] = dict(_FONT_DEFAULTS) if full else {} + for c in el if el is not None else (): + name, val = _ln(c.tag), c.get("val") + if name in ("name", "rFont"): + d["name"] = val + elif name == "sz": + d["size"] = _float(val) + elif name in ("b", "i", "strike"): + d[{"b": "bold", "i": "italic"}.get(name, name)] = _bool(val, True) + elif name == "u": + d["underline"] = val or "single" + elif name == "vertAlign": + d["vert_align"] = val or "baseline" + elif name == "color": + d["color"] = _color(c) + return d + + +def _fill(el: Any, full: bool) -> dict[str, Any]: + if el is None: + return {"pattern": "none"} if full else {} + gf = _kid(el, "gradientFill") + if gf is not None: + return { + "gradient": { + "type": gf.get("type", "linear"), + "degree": _float(gf.get("degree"), 0.0), + "left": _float(gf.get("left"), 0.0), + "right": _float(gf.get("right"), 0.0), + "top": _float(gf.get("top"), 0.0), + "bottom": _float(gf.get("bottom"), 0.0), + "stops": [ + [_float(s.get("position"), 0.0), _color(_kid(s, "color"))] + for s in _kids(gf, "stop") + ], + } + } + pf = _kid(el, "patternFill") + if pf is None: + return {"pattern": "none"} if full else {} + pattern = pf.get("patternType") + fg, bg = _color(_kid(pf, "fgColor")), _color(_kid(pf, "bgColor")) + if not full: + # Differential (dxf) fills: an absent patternType means solid, and a + # solid dxf fill paints its bgColor (fgColor when bgColor is absent). + pattern = pattern or "solid" + if pattern == "none": + return {"pattern": "none"} + if pattern == "solid": + return {"pattern": "solid", "color": bg if bg is not None else fg} + return {"pattern": pattern, "fg": fg, "bg": bg} + pattern = pattern or "none" + if pattern == "none": + return {"pattern": "none"} + if pattern == "solid": + return {"pattern": "solid", "fg": fg} + return {"pattern": pattern, "fg": fg, "bg": bg} + + +def _border(el: Any, full: bool) -> dict[str, Any]: + sides: dict[str, Any] = {} + for c in el if el is not None else (): + name = {"start": "left", "end": "right"}.get(_ln(c.tag), _ln(c.tag)) + if name in (*_SIDES, "diagonal", "vertical", "horizontal"): + style = c.get("style") + if style is None and not full: + continue # a differential side without style changes nothing + sides[name] = ( + {"style": "none"} + if (style or "none") == "none" + else {"style": style, "color": _color(_kid(c, "color"))} + ) + up = _bool(_attr(el, "diagonalUp"), False) if el is not None else False + down = _bool(_attr(el, "diagonalDown"), False) if el is not None else False + if not full: + if up or down: + sides["diagonal_up"], sides["diagonal_down"] = up, down + else: + sides.pop("diagonal", None) + return sides + out = {s: sides.get(s, {"style": "none"}) for s in _SIDES} + if up or down: + out["diagonal"] = { + "up": up, + "down": down, + **sides.get("diagonal", {"style": "none"}), + } + return out + + +def _alignment(el: Any, full: bool) -> dict[str, Any]: + out: dict[str, Any] = {} + for attr, (name, default, kind) in _ALIGN_ATTRS.items(): + raw = el.get(attr) if el is not None else None + if raw is None: + if full: + out[name] = default + continue + if kind is bool: + out[name] = _bool(raw, default) + elif kind is int: + out[name] = _int(raw, default) + else: + out[name] = raw + return out + + +def _protection(el: Any, full: bool) -> dict[str, Any]: + out: dict[str, Any] = {} + for attr, default in (("locked", True), ("hidden", False)): + raw = el.get(attr) if el is not None else None + if raw is not None or full: + out[attr] = _bool(raw, default) + return out + + +_SELF_LITERAL = frozenset("$-+/():!^&'~{}<>= ") + + +def _numfmt_code(code: str) -> str: + """Drop backslash escapes of characters that display literally anyway.""" + out: list[str] = [] + i = 0 + n = len(code) + while i < n: + ch = code[i] + if ch == '"': + j = code.find('"', i + 1) + j = n if j < 0 else j + 1 + out.append(code[i:j]) + i = j + elif ch == "\\" and i + 1 < n: + nxt = code[i + 1] + out.append(nxt if nxt in _SELF_LITERAL else code[i : i + 2]) + i += 2 + else: + out.append(ch) + i += 1 + return "".join(out) + + +def _builtin_numfmt(nid: int) -> str: + code = _BUILTIN_NUMFMTS.get(nid) + return _numfmt_code(code) if code is not None else f"builtin:{nid}" + + +class _Styles: + def __init__(self, root: Any) -> None: + palette = _kids(_kid(_kid(root, "colors"), "indexedColors"), "rgbColor") + resolved = list(_DEFAULT_PALETTE) + for i, c in enumerate(palette[: len(resolved)]): + rgb = (c.get("rgb") or "").strip().upper() + resolved[i] = rgb[-6:] if len(rgb) >= 6 else resolved[i] + # Every color parsed from here on (styles, shared strings, sheets) is + # resolved through this workbook's palette. + _PALETTE.set(tuple(resolved)) + self.numfmts: dict[int, str] = {} + for nf in _kids(_kid(root, "numFmts"), "numFmt"): + nid = _int(nf.get("numFmtId")) + if nid is not None: + self.numfmts[nid] = _numfmt_code(nf.get("formatCode", "")) + self.fonts = [_font(f, True) for f in _kids(_kid(root, "fonts"), "font")] + self.fills = [_fill(f, True) for f in _kids(_kid(root, "fills"), "fill")] + self.borders = [ + _border(b, True) for b in _kids(_kid(root, "borders"), "border") + ] + self.xfs = _kids(_kid(root, "cellXfs"), "xf") + self.dxf_els = _kids(_kid(root, "dxfs"), "dxf") + self.table: dict[str, dict[str, Any]] = {} + self._keys: dict[int, str] = {} + self.default_style = self._resolve(0) + self.default_key = self.key(0) + + def numfmt(self, nid: int) -> str: + if nid in self.numfmts: + return self.numfmts[nid] + return _builtin_numfmt(nid) + + @staticmethod + def _pick(table: list[Any], index: int | None, default: Any) -> Any: + if index is None: + index = 0 + if 0 <= index < len(table): + return table[index] + return default if index == 0 and not table else f"invalid:{index}" + + def _resolve(self, index: int) -> dict[str, Any]: + if not (0 <= index < len(self.xfs)): + if index == 0: + xf = None + else: + return {"invalid_xf": index} + else: + xf = self.xfs[index] + get = (lambda a: xf.get(a)) if xf is not None else (lambda a: None) + return { + "number_format": self.numfmt(_int(get("numFmtId"), 0) or 0), + "font": self._pick(self.fonts, _int(get("fontId")), dict(_FONT_DEFAULTS)), + "fill": self._pick(self.fills, _int(get("fillId")), {"pattern": "none"}), + "border": self._pick( + self.borders, _int(get("borderId")), _border(None, True) + ), + "alignment": _alignment(_kid(xf, "alignment"), True), + "protection": _protection(_kid(xf, "protection"), True), + } + + def key(self, index: int) -> str: + if index not in self._keys: + self._keys[index] = self.add(self._resolve(index)) + return self._keys[index] + + def add(self, style: dict[str, Any]) -> str: + k = _key(style) + self.table.setdefault(k, style) + return k + + def font(self, index: int) -> dict[str, Any]: + font = self.table[self.key(index)].get("font") + return font if isinstance(font, dict) else dict(_FONT_DEFAULTS) + + def dxf(self, index: int | None) -> dict[str, Any] | None: + if index is None or not (0 <= index < len(self.dxf_els)): + return None + return _dxf(self.dxf_els[index]) + + +def _dxf(el: Any) -> dict[str, Any]: + out: dict[str, Any] = {} + font = _kid(el, "font") + if font is not None: + out["font"] = _font(font, False) + nf = _kid(el, "numFmt") + if nf is not None: + code = nf.get("formatCode") + nid = _int(nf.get("numFmtId"), 0) or 0 + out["number_format"] = ( + _numfmt_code(code) if code is not None else _builtin_numfmt(nid) + ) + fill = _kid(el, "fill") + if fill is not None: + out["fill"] = _fill(fill, False) + align = _kid(el, "alignment") + if align is not None: + out["alignment"] = _alignment(align, False) + border = _kid(el, "border") + if border is not None: + out["border"] = _border(border, False) + prot = _kid(el, "protection") + if prot is not None: + out["protection"] = _protection(prot, False) + return out + + +# --------------------------------------------------------------------------- +# Generic canonical dump (filter criteria, CF parameters) +# --------------------------------------------------------------------------- + +_DUMP_DEFAULTS = { + ("dataBar", "minLength"): "10", + ("dataBar", "maxLength"): "90", + ("dataBar", "showValue"): "1", + ("dataBar", "border"): "0", + ("dataBar", "gradient"): "1", + ("dataBar", "direction"): "context", + ("dataBar", "negativeBarColorSameAsPositive"): "0", + ("dataBar", "negativeBarBorderColorSameAsPositive"): "1", + ("dataBar", "axisPosition"): "automatic", + ("iconSet", "custom"): "0", + ("iconSet", "iconSet"): "3TrafficLights1", + ("iconSet", "showValue"): "1", + ("iconSet", "percent"): "1", + ("iconSet", "reverse"): "0", + ("cfvo", "gte"): "1", + ("filters", "blank"): "0", + ("customFilters", "and"): "0", + ("customFilter", "operator"): "equal", + ("filterColumn", "hiddenButton"): "0", + ("filterColumn", "showButton"): "1", +} +_COLOR_TAGS = { + "color", + "fgColor", + "bgColor", + "negativeFillColor", + "negativeBorderColor", + "axisColor", + "borderColor", + "fillColor", +} +# cfvo types whose `val` is ignored (the threshold is the data's min/max). +_CFVO_NO_VALUE = ("min", "max", "autoMin", "autoMax") + + +def _dump(el: Any) -> Any: + tag = _ln(el.tag) + if tag in _COLOR_TAGS: + return {"tag": tag, "color": _color(el)} + attrs: dict[str, str] = {} + for key, val in el.attrib.items(): + name = _ln(key) + if key.startswith("{") and key[1:].split("}", 1)[0].endswith("relationships"): + continue + if tag == "cfvo" and name == "val" and el.get("type") in _CFVO_NO_VALUE: + continue + val = {"true": "1", "false": "0"}.get(val.lower(), val) + if _DUMP_DEFAULTS.get((tag, name)) == val: + continue + attrs[name] = val + out: dict[str, Any] = {"tag": tag} + if attrs: + out["attrs"] = dict(sorted(attrs.items())) + text = (el.text or "").strip() + if text: + out["text"] = text + children = [_dump(c) for c in el if isinstance(c.tag, str)] + if children: + out["children"] = children + return out + + +# --------------------------------------------------------------------------- +# Strings and dates +# --------------------------------------------------------------------------- + + +def _string_item(si: Any) -> tuple[str, list[tuple[str, dict[str, Any]]] | None]: + runs: list[tuple[str, dict[str, Any]]] = [] + has_runs = False + for c in si: + name = _ln(c.tag) + if name == "t": + runs.append((_unescape(c.text or ""), {})) + elif name == "r": + has_runs = True + t = _kid(c, "t") + runs.append( + ( + _unescape((t.text or "") if t is not None else ""), + _font(_kid(c, "rPr"), False), + ) + ) + text = "".join(t for t, _ in runs) + return text, (runs if has_runs else None) + + +def _effective_runs( + runs: list[tuple[str, dict[str, Any]]] | None, cell_font: dict[str, Any] +) -> list[dict[str, Any]] | None: + if not runs: + return None + merged: list[dict[str, Any]] = [] + for text, props in runs: + if not text: + continue + font = {**cell_font, **props} + if merged and merged[-1]["font"] == font: + merged[-1]["text"] += text + else: + merged.append({"text": text, "font": font}) + if all(r["font"] == cell_font for r in merged): + return None + return merged + + +def _date_serial(text: str, date1904: bool) -> float | None: + raw = text.strip() + try: + if "T" in raw or "-" in raw: + value = _dt.datetime.fromisoformat(raw).replace(tzinfo=None) + else: + t = _dt.time.fromisoformat(raw) + return ( + t.hour * 3600 + t.minute * 60 + t.second + t.microsecond / 1e6 + ) / 86400 + except ValueError: + return None + epoch = _dt.datetime(1904, 1, 1) if date1904 else _dt.datetime(1899, 12, 30) + delta = value - epoch + serial = delta.days + delta.seconds / 86400 + delta.microseconds / 86400e6 + if not date1904 and value < _dt.datetime(1900, 3, 1): + serial -= 1 + return serial + + +# --------------------------------------------------------------------------- +# Extraction +# --------------------------------------------------------------------------- + + +def extract(path: Path) -> dict[str, Any]: + pkg = _Package(Path(path)) + wb_part = next( + ( + r.target + for r in pkg.rels("").values() + if r.kind == "officeDocument" and not r.external and r.target in pkg.parts + ), + None, + ) + if wb_part is None: + raise ValueError("package has no workbook part") + wb = pkg.xml(wb_part) + if _ln(wb.tag) != "workbook": + raise ValueError(f"main part {wb_part} is not a workbook") + + model: dict[str, Any] = {f: {} for f in FEATURES} + date1904 = _bool(_attr(_kid(wb, "workbookPr"), "date1904"), False) + + styles_parts = pkg.targets(wb_part, "styles") + styles = _Styles(pkg.xml(styles_parts[0]) if styles_parts else None) + + shared: list[tuple[str, Any]] = [] + for part in pkg.targets(wb_part, "sharedStrings")[:1]: + shared = [_string_item(si) for si in _kids(pkg.xml(part), "si")] + + persons: dict[str, str] = {} + for part in pkg.targets(wb_part, "person"): + for p in _kids(pkg.xml(part), "person"): + persons[p.get("id", "")] = p.get("displayName", "") + + # Sheets + sheets: list[tuple[str, str, str | None]] = [] # name, kind, part + wb_sheets: dict[str, Any] = {} + for sh in _kids(_kid(wb, "sheets"), "sheet"): + name = sh.get("name", "") + rel = pkg.deref(wb_part, _rel_attr(sh, "id")) + part = ( + rel.target if rel and not rel.external and rel.target in pkg.parts else None + ) + kind = {"xlMacrosheet": "macrosheet", "xlIntlMacrosheet": "macrosheet"}.get( + rel.kind if rel else "", rel.kind if rel else "missing" + ) + if part is None: + kind = "missing" + sheets.append((name, kind, part)) + wb_sheets[name] = {"kind": kind, "state": sh.get("state", "visible")} + sheet_names = [s[0] for s in sheets] + model["workbook"] = { + "sheet_order": sheet_names, + "sheets": wb_sheets, + "date1904": date1904, + } + + # Defined names + print_titles: dict[str, dict[str, str]] = {} + print_areas: dict[str, list[str]] = {} + names: dict[str, Any] = {} + for dn in _kids(_kid(wb, "definedNames"), "definedName"): + name = dn.get("name", "") + local = _int(dn.get("localSheetId")) + scope = "" + if local is not None: + scope = sheet_names[local] if 0 <= local < len(sheet_names) else f"#{local}" + refers = dn.text or "" + lname = name.lower() + if lname == "_xlnm._filterdatabase": + continue + if lname == "_xlnm.print_titles" and scope: + titles: dict[str, str] = {} + for area in _split_areas(refers): + rect = _parse_range(_strip_sheet(area)) + if rect and rect[1] == 1 and rect[3] == MAX_COL: + titles["rows"] = f"{rect[0]}:{rect[2]}" + elif rect and rect[0] == 1 and rect[2] == MAX_ROW: + titles["cols"] = f"{_col_name(rect[1])}:{_col_name(rect[3])}" + else: + titles["other"] = _normalize_formula(area) or "" + print_titles[scope] = titles + continue + if lname == "_xlnm.print_area" and scope: + print_areas[scope] = [ + _canon_ref(_strip_sheet(a)) + if _parse_range(_strip_sheet(a)) + else _normalize_formula(a) or "" + for a in _split_areas(refers) + ] + continue + entry: dict[str, Any] = {"refers_to": _normalize_formula(refers)} + if _bool(dn.get("hidden"), False): + entry["hidden"] = True + names[f"{scope}!{name}"] = entry + model["defined_names"] = names + + # Workbook-level package features + model["protection"] = { + "workbook": { + "lock_structure": _bool( + _attr(_kid(wb, "workbookProtection"), "lockStructure"), False + ), + "lock_windows": _bool( + _attr(_kid(wb, "workbookProtection"), "lockWindows"), False + ), + }, + "sheets": {}, + } + model["external_links"] = {"count": len(pkg.targets(wb_part, "externalLink"))} + model["vba"] = {"present": bool(pkg.targets(wb_part, "vbaProject"))} + theme_colors = _theme_colors(pkg, wb_part) + model["theme"] = {} + + model["cell_styles"] = {"default": styles.default_key, "table": {}, "sheets": {}} + for feature in FEATURES: + if feature in ( + "workbook", + "defined_names", + "external_links", + "vba", + "theme", + "protection", + "cell_styles", + ): + continue + model[feature] = {name: {} for name in sheet_names} + for name in sheet_names: + model["cell_styles"]["sheets"][name] = {} + model["protection"]["sheets"][name] = False + + for name, kind, part in sheets: + if part is None: + continue + root = pkg.xml(part) + prot = _kid(root, "sheetProtection") + if _ln(root.tag) == "chartsheet": + model["protection"]["sheets"][name] = _bool(_attr(prot, "content"), False) + else: + model["protection"]["sheets"][name] = _bool(_attr(prot, "sheet"), False) + _drawings(pkg, part, root, name, model) + if _kid(root, "sheetData") is None: + continue + _worksheet( + pkg, + part, + root, + name, + model, + styles, + shared, + persons, + date1904, + print_titles.get(name), + print_areas.get(name), + ) + model["cell_styles"]["table"] = dict(sorted(styles.table.items())) + dumped = json.dumps(model) + used_theme = sorted({int(m) for m in _THEME_RE.findall(dumped)}) + if used_theme: + model["theme"]["colors"] = { + str(i): theme_colors.get(_THEME_SLOTS[i]) if i < len(_THEME_SLOTS) else None + for i in used_theme + } + return model + + +# SpreadsheetML theme color indexes (ECMA-376 Part 1, 18.3.1.15 / 20.1.6.2): +# the first two light/dark pairs are swapped relative to clrScheme order. +_THEME_SLOTS = ( + "lt1", + "dk1", + "lt2", + "dk2", + "accent1", + "accent2", + "accent3", + "accent4", + "accent5", + "accent6", + "hlink", + "folHlink", +) + + +def _theme_colors(pkg: _Package, wb_part: str) -> dict[str, Any]: + colors: dict[str, Any] = {} + parts = pkg.targets(wb_part, "theme") + if not parts: + return colors + scheme = _kid(_kid(pkg.xml(parts[0]), "themeElements"), "clrScheme") + for slot in scheme if scheme is not None else (): + value = None + for c in slot: + tag = _ln(c.tag) + if tag == "srgbClr": + value = (c.get("val") or "").upper() + elif tag == "sysClr": + last = c.get("lastClr") + value = last.upper() if last else f"system:{c.get('val')}" + else: + value = f"{tag}:{c.get('val')}" + break + colors[_ln(slot.tag)] = value + return colors + + +_THEME_RE = re.compile(r'"theme:(\d+)') + + +def _worksheet( + pkg: _Package, + part: str, + root: Any, + name: str, + model: dict[str, Any], + styles: _Styles, + shared: list[tuple[str, Any]], + persons: dict[str, str], + date1904: bool, + print_titles: dict[str, str] | None, + print_area: list[str] | None, +) -> None: + default_key = styles.default_key + + # Columns + col_props: dict[int, dict[str, Any]] = {} + col_style: dict[int, str] = {} + for col in _kids(_kid(root, "cols"), "col"): + lo, hi = _int(col.get("min")), _int(col.get("max")) + if lo is None or hi is None: + continue + props: dict[str, Any] = {} + width = _float(col.get("width")) + if width is not None: + props["width"] = width + if _bool(col.get("hidden"), False): + props["hidden"] = True + level = _int(col.get("outlineLevel"), 0) + if level: + props["outline_level"] = level + if _bool(col.get("collapsed"), False): + props["collapsed"] = True + skey = styles.key(_int(col.get("style"), 0) or 0) + if skey != default_key: + props["style"] = skey + for c in range(max(lo, 1), min(hi, MAX_COL) + 1): + if props: + col_props[c] = props + if skey != default_key: + col_style[c] = skey + columns: dict[str, Any] = {} + run_start = prev = None + for c in sorted(col_props) + [None]: + if run_start is not None and ( + c is None or c != prev + 1 or col_props[c] != col_props[run_start] + ): + columns[f"{_col_name(run_start)}:{_col_name(prev)}"] = col_props[run_start] + run_start = None + if c is not None and run_start is None: + run_start = c + prev = c + model["columns"][name] = columns + + # Rows and cells + rows: dict[str, Any] = {} + row_styles: dict[int, str] = {} + fmt = _kid(root, "sheetFormatPr") + if fmt is not None: + default_row: dict[str, Any] = {} + if _bool(fmt.get("customHeight"), False) and fmt.get("defaultRowHeight"): + default_row["height"] = _float(fmt.get("defaultRowHeight")) + if _bool(fmt.get("zeroHeight"), False): + default_row["hidden"] = True + if default_row: + rows["_default"] = default_row + cells: dict[str, Any] = {} + formulas: dict[str, Any] = {} + cell_styles: dict[str, str] = {} + shared_anchor: dict[str, tuple[int, int, str]] = {} + shared_users: list[tuple[str, int, int, str]] = [] + row_num = 0 + for row in _kids(_kid(root, "sheetData"), "row"): + row_num = _int(row.get("r"), row_num + 1) or row_num + 1 + props = {} + if _bool(row.get("customHeight"), False) and row.get("ht") is not None: + props["height"] = _float(row.get("ht")) + if _bool(row.get("hidden"), False): + props["hidden"] = True + level = _int(row.get("outlineLevel"), 0) + if level: + props["outline_level"] = level + if _bool(row.get("collapsed"), False): + props["collapsed"] = True + row_key = None + if _bool(row.get("customFormat"), False): + row_key = styles.key(_int(row.get("s"), 0) or 0) + row_styles[row_num] = row_key + if row_key != default_key: + props["style"] = row_key + if props: + rows[str(row_num)] = props + col_num = 0 + for c in _kids(row, "c"): + ref = c.get("r") + parsed = _parse_cell(ref) if ref else None + if parsed: + row_here, col_num = parsed + else: + row_here, col_num = row_num, col_num + 1 + addr = f"{_col_name(col_num)}{row_here}" + s_index = _int(c.get("s"), 0) or 0 + skey = styles.key(s_index) + background = ( + row_key if row_key is not None else col_style.get(col_num, default_key) + ) + if skey != background: + cell_styles[addr] = skey + value = _cell_value(c, shared, styles.font(s_index), date1904) + if value is not None: + cells[addr] = value + f = _kid(c, "f") + if f is None: + continue + ftype = f.get("t", "normal") + text = f.text if f.text and f.text.strip() else None + if ftype == "shared": + si = f.get("si", "") + if text is not None and si not in shared_anchor: + shared_anchor[si] = (row_here, col_num, text) + formulas[addr] = {"text": _normalize_formula(text)} + elif text is not None: + formulas[addr] = {"text": _normalize_formula(text)} + else: + shared_users.append((addr, row_here, col_num, si)) + elif ftype == "array": + entry: dict[str, Any] = {"text": _normalize_formula(text)} + entry["array"] = _canon_ref(f.get("ref") or addr) + formulas[addr] = entry + elif ftype == "dataTable": + attrs = { + k: v + for k, v in sorted(f.attrib.items()) + if k in ("ref", "dt2D", "dtr", "del1", "del2", "r1", "r2") + } + if "ref" in attrs: + attrs["ref"] = _canon_ref(attrs["ref"]) or "" + formulas[addr] = {"text": _normalize_formula(text), "data_table": attrs} + elif text is not None: + formulas[addr] = {"text": _normalize_formula(text)} + for addr, r, col, si in shared_users: + anchor = shared_anchor.get(si) + if anchor is None: + formulas[addr] = {"text": None, "shared_without_anchor": True} + continue + formulas[addr] = { + "text": _normalize_formula( + _translate(anchor[2], r - anchor[0], col - anchor[1]) + ) + } + model["rows"][name] = rows + model["cells"][name] = cells + model["formulas"][name] = formulas + merges = [ + rect + for rect in ( + _parse_range(m.get("ref") or "") + for m in _kids(_kid(root, "mergeCells"), "mergeCell") + ) + if rect + ] + if merges: + _merge_styles(merges, cell_styles, row_styles, col_style, styles) + model["cell_styles"]["sheets"][name] = cell_styles + + # Merged cells + model["merged_cells"][name] = {_render_range(*rect): True for rect in merges} + + # Views + views: dict[str, Any] = {} + view = _kid(_kid(root, "sheetViews"), "sheetView") + if view is not None: + pane = _kid(view, "pane") + if pane is not None and pane.get("state") in ("frozen", "frozenSplit"): + views["freeze"] = { + "cols": _int(pane.get("xSplit"), 0), + "rows": _int(pane.get("ySplit"), 0), + } + views["right_to_left"] = _bool(_attr(view, "rightToLeft"), False) + views["show_gridlines"] = _bool(_attr(view, "showGridLines"), True) + views["show_headers"] = _bool(_attr(view, "showRowColHeaders"), True) + views["zoom"] = _int(_attr(view, "zoomScale"), 100) + sheet_pr = _kid(root, "sheetPr") + tab = _color(_kid(sheet_pr, "tabColor")) + if tab is not None: + views["tab_color"] = tab + model["views"][name] = views + + # Auto filter + af = _kid(root, "autoFilter") + if af is not None: + entry = {"ref": _canon_ref(af.get("ref"))} + cols = {fc.get("colId", ""): _dump(fc) for fc in _kids(af, "filterColumn")} + if cols: + entry["columns"] = cols + model["auto_filters"][name] = entry + + ext_dv: list[Any] = [] + ext_cf: list[Any] = [] + for ext in _kids(_kid(root, "extLst"), "ext"): + for c in ext: + if _ln(c.tag) == "dataValidations": + ext_dv.extend(_kids(c, "dataValidation")) + elif _ln(c.tag) == "conditionalFormattings": + ext_cf.extend(_kids(c, "conditionalFormatting")) + + model["data_validations"][name] = _validations( + _kids(_kid(root, "dataValidations"), "dataValidation"), ext_dv + ) + model["conditional_formats"][name] = _conditional_formats( + _kids(root, "conditionalFormatting"), ext_cf, styles + ) + + # Hyperlinks + links: dict[str, Any] = {} + for h in _kids(_kid(root, "hyperlinks"), "hyperlink"): + entry = {} + rel = pkg.deref(part, _rel_attr(h, "id")) + if rel is not None: + entry["target"] = rel.target + if h.get("location"): + entry["location"] = h.get("location") + if h.get("tooltip"): + entry["tooltip"] = h.get("tooltip") + links[_canon_ref(h.get("ref", "")) or ""] = entry + model["hyperlinks"][name] = links + + # Comments + notes: dict[str, Any] = {} + for cpart in pkg.targets(part, "comments"): + croot = pkg.xml(cpart) + authors = [a.text or "" for a in _kids(_kid(croot, "authors"), "author")] + for cm in _kids(_kid(croot, "commentList"), "comment"): + aid = _int(cm.get("authorId")) + notes[_canon_ref(cm.get("ref", "")) or ""] = { + "author": authors[aid] + if aid is not None and 0 <= aid < len(authors) + else None, + "text": _text_of(_kid(cm, "text")), + } + threads: dict[str, list[Any]] = {} + for tpart in pkg.targets(part, "threadedComment"): + for tc in _kids(pkg.xml(tpart), "threadedComment"): + threads.setdefault(_canon_ref(tc.get("ref", "")) or "", []).append( + { + "author": persons.get(tc.get("personId", "")), + "text": _unescape(_kid(tc, "text").text or "") + if _kid(tc, "text") is not None + else "", + } + ) + for addr in threads: + notes.pop(addr, None) + model["comments"][name] = {"notes": notes, "threads": threads} + + # Page setup + ps = _kid(root, "pageSetup") + fit = _bool(_attr(_kid(sheet_pr, "pageSetUpPr"), "fitToPage"), False) + orientation = _attr(ps, "orientation") or "default" + setup: dict[str, Any] = { + "orientation": "portrait" if orientation == "default" else orientation, + "paper_size": _int(_attr(ps, "paperSize"), 1), + "fit_to_page": fit, + } + if fit: + setup["fit_width"] = _int(_attr(ps, "fitToWidth"), 1) + setup["fit_height"] = _int(_attr(ps, "fitToHeight"), 1) + else: + setup["scale"] = _int(_attr(ps, "scale"), 100) + pm = _kid(root, "pageMargins") + setup["margins"] = { + side: _float(_attr(pm, side), default) + for side, default in ( + ("left", 0.7), + ("right", 0.7), + ("top", 0.75), + ("bottom", 0.75), + ("header", 0.3), + ("footer", 0.3), + ) + } + hf = _kid(root, "headerFooter") + if hf is not None: + hf_out: dict[str, Any] = {} + for c in hf: + sections = _hf_sections(_unescape(c.text or "")) + if sections: + hf_out[_ln(c.tag)] = sections + for flag in ("differentOddEven", "differentFirst"): + if _bool(hf.get(flag), False): + hf_out[flag] = True + if hf_out: + setup["header_footer"] = hf_out + if print_titles: + setup["print_titles"] = print_titles + if print_area: + setup["print_area"] = print_area + model["page_setup"][name] = setup + + # Tables + tables: dict[str, Any] = {} + for tpart in pkg.targets(part, "table"): + t = pkg.xml(tpart) + info = _kid(t, "tableStyleInfo") + entry = { + "ref": _canon_ref(t.get("ref")), + "columns": [ + _unescape(tc.get("name", "")) + for tc in _kids(_kid(t, "tableColumns"), "tableColumn") + ], + "header_row": (_int(t.get("headerRowCount"), 1) or 0) > 0, + "totals_row": (_int(t.get("totalsRowCount"), 0) or 0) > 0, + } + if info is not None: + entry["style"] = { + "name": info.get("name"), + **{ + flag: _bool(info.get(flag), False) + for flag in ( + "showFirstColumn", + "showLastColumn", + "showRowStripes", + "showColumnStripes", + ) + }, + } + tables[t.get("displayName") or t.get("name") or tpart] = entry + model["tables"][name] = tables + + # Pivot tables + pivots: dict[str, Any] = {} + for ppart in pkg.targets(part, "pivotTable"): + p = pkg.xml(ppart) + source: dict[str, Any] = {} + for cpart in pkg.targets(ppart, "pivotCacheDefinition")[:1]: + cs = _kid(pkg.xml(cpart), "cacheSource") + source["type"] = _attr(cs, "type") or "worksheet" + ws = _kid(cs, "worksheetSource") + if ws is not None: + for attr in ("sheet", "name"): + if ws.get(attr): + source[attr] = ws.get(attr) + if ws.get("ref"): + source["ref"] = _canon_ref(ws.get("ref")) + pivots[p.get("name") or ppart] = { + "location": _canon_ref(_attr(_kid(p, "location"), "ref")), + "source": source, + } + model["pivot_tables"][name] = pivots + + +def _merge_styles( + merges: list[tuple[int, int, int, int]], + cell_styles: dict[str, str], + row_styles: dict[int, str], + col_style: dict[int, str], + styles: _Styles, +) -> None: + """Replace the styles of merged cells by what a merged area shows. + + A merged area renders the anchor (top-left) cell's style, except that its + border is the per-cell perimeter: top sides of the top row, bottom sides + of the bottom row, left sides of the left column, right sides of the right + column (a side list collapses to one value when uniform). Styles of + covered cells and interior borders are not rendered and are dropped. + """ + + def effective(r: int, c: int) -> dict[str, Any]: + key = cell_styles.get(f"{_col_name(c)}{r}") + if key is None: + key = row_styles.get(r) or col_style.get(c, styles.default_key) + return styles.table[key] + + def side(r: int, c: int, name: str) -> Any: + border = effective(r, c).get("border") + return ( + border.get(name, {"style": "none"}) if isinstance(border, dict) else border + ) + + def collapse(values: list[Any]) -> Any: + return values[0] if all(v == values[0] for v in values) else values + + composed: dict[str, str] = {} + for r1, c1, r2, c2 in merges: + anchor = effective(r1, c1) + border = { + "top": collapse([side(r1, c, "top") for c in range(c1, c2 + 1)]), + "bottom": collapse([side(r2, c, "bottom") for c in range(c1, c2 + 1)]), + "left": collapse([side(r, c1, "left") for r in range(r1, r2 + 1)]), + "right": collapse([side(r, c2, "right") for r in range(r1, r2 + 1)]), + } + anchor_border = anchor.get("border") + if isinstance(anchor_border, dict) and "diagonal" in anchor_border: + border["diagonal"] = anchor_border["diagonal"] + composed[f"{_col_name(c1)}{r1}"] = styles.add({**anchor, "border": border}) + short: dict[int, list[tuple[int, int]]] = {} + tall: list[tuple[int, int, int, int]] = [] + for r1, c1, r2, c2 in merges: + if r2 - r1 > 10000: + tall.append((r1, c1, r2, c2)) + continue + for r in range(r1, r2 + 1): + short.setdefault(r, []).append((c1, c2)) + for addr in list(cell_styles): + r, c = _parse_cell(addr) or (0, 0) + if any(c1 <= c <= c2 for c1, c2 in short.get(r, ())) or any( + r1 <= r <= r2 and c1 <= c <= c2 for r1, c1, r2, c2 in tall + ): + del cell_styles[addr] + cell_styles.update(composed) + + +def _cell_value( + c: Any, shared: list[tuple[str, Any]], cell_font: dict[str, Any], date1904: bool +) -> dict[str, Any] | None: + t = c.get("t", "n") + v = _kid(c, "v") + raw = v.text if v is not None else None + if t == "inlineStr": + is_el = _kid(c, "is") + if is_el is None: + return None if raw is None else {"type": "s", "value": _unescape(raw)} + text, runs = _string_item(is_el) + out: dict[str, Any] = {"type": "s", "value": text} + eff = _effective_runs(runs, cell_font) + if eff: + out["runs"] = eff + return out + if raw is None: + return None + if t == "s": + idx = _int(raw) + if idx is None or not (0 <= idx < len(shared)): + return {"type": "invalid", "value": f"sst:{raw}"} + text, runs = shared[idx] + out = {"type": "s", "value": text} + eff = _effective_runs(runs, cell_font) + if eff: + out["runs"] = eff + return out + if t == "str": + return {"type": "s", "value": _unescape(raw)} + if t == "b": + return {"type": "b", "value": _bool(raw, False)} + if t == "e": + return {"type": "e", "value": raw.strip()} + if t == "d": + serial = _date_serial(raw, date1904) + if serial is None: + return {"type": "invalid", "value": raw} + return {"type": "n", "value": float(serial)} + if not raw.strip(): + return None + number = _float(raw) + if number is None: + return {"type": "invalid", "value": raw} + return {"type": "n", "value": number} + + +def _formula_texts(el: Any) -> list[str | None]: + """formula / formula1 / formula2 / xm:f children, normalized, in order.""" + out: list[str | None] = [] + for c in el: + tag = _ln(c.tag) + if tag in ("formula", "f"): + out.append(_normalize_formula(c.text or "")) + return out + + +def _dv_formula(el: Any, which: str) -> str | None: + f = _kid(el, which) + if f is None: + return None + inner = _kid(f, "f") + return _normalize_formula((inner.text if inner is not None else f.text) or "") + + +# Validation types that use `operator`; formula2 is read only by these types +# with between/notBetween. +_DV_OPERATOR_TYPES = ("whole", "decimal", "date", "time", "textLength") + + +def _validations(main: list[Any], ext: list[Any]) -> dict[str, Any]: + groups: dict[str, dict[str, Any]] = {} + for dv in [*main, *ext]: + dv_type = dv.get("type", "none") + operator = dv.get("operator", "between") + params: dict[str, Any] = { + "type": dv_type, + "operator": operator if dv_type in _DV_OPERATOR_TYPES else None, + "formula1": _dv_formula(dv, "formula1") if dv_type != "none" else None, + "formula2": ( + _dv_formula(dv, "formula2") + if dv_type in _DV_OPERATOR_TYPES + and operator in ("between", "notBetween") + else None + ), + "allow_blank": _bool(dv.get("allowBlank"), False), + "show_dropdown": not _bool(dv.get("showDropDown"), False), + "show_input_message": _bool(dv.get("showInputMessage"), False), + "show_error_message": _bool(dv.get("showErrorMessage"), False), + "error_style": dv.get("errorStyle", "stop"), + "error_title": dv.get("errorTitle"), + "error": dv.get("error"), + "prompt_title": dv.get("promptTitle"), + "prompt": dv.get("prompt"), + } + params = {k: v for k, v in params.items() if v is not None} + sqref = dv.get("sqref") + if sqref is None: + sq = _kid(dv, "sqref") + sqref = sq.text if sq is not None else "" + key = _key(params) + group = groups.setdefault(key, {**params, "_areas": []}) + group["_areas"].append(sqref or "") + out: dict[str, Any] = {} + for key in sorted(groups): + group = groups[key] + areas = group.pop("_areas") + group["sqref"] = _canon_sqref(" ".join(areas)) + out[key] = group + return out + + +_CF_ATTR_DEFAULTS = { + "percent": False, + "bottom": False, + "aboveAverage": True, + "equalAverage": False, +} +_CF_TEXT_TYPES = ("containsText", "notContainsText", "beginsWith", "endsWith") +# Attributes each rule type reads (ECMA-376 18.3.1.10); others are ignored. +_CF_TYPE_ATTRS = { + **{t: ("text",) for t in _CF_TEXT_TYPES}, + "timePeriod": ("timePeriod",), + "top10": ("rank", "percent", "bottom"), + "aboveAverage": ("aboveAverage", "equalAverage", "stdDev"), +} +# Rule types whose condition is not a formula; formula children are ignored. +_CF_NO_FORMULA_TYPES = ( + "aboveAverage", + "top10", + "duplicateValues", + "uniqueValues", + "colorScale", + "dataBar", + "iconSet", +) + + +def _cf_rule(rule: Any, sqref: str, styles: _Styles) -> dict[str, Any]: + rtype = rule.get("type") + entry: dict[str, Any] = {"sqref": _canon_sqref(sqref), "type": rtype} + if rule.get("operator") and rtype in ("cellIs", *_CF_TEXT_TYPES): + entry["operator"] = rule.get("operator") + formulas = _formula_texts(rule) + if formulas and rtype not in _CF_NO_FORMULA_TYPES: + entry["formulas"] = formulas + if _bool(rule.get("stopIfTrue"), False): + entry["stop_if_true"] = True + attrs: dict[str, Any] = {} + for attr in _CF_TYPE_ATTRS.get(rtype or "", ()): + if attr in _CF_ATTR_DEFAULTS: + val = _bool(rule.get(attr), _CF_ATTR_DEFAULTS[attr]) + if val != _CF_ATTR_DEFAULTS[attr]: + attrs[attr] = val + elif rule.get(attr) is not None: + attrs[attr] = rule.get(attr) + if attrs: + entry["attrs"] = attrs + dxf = styles.dxf(_int(rule.get("dxfId"))) + inline_dxf = _kid(rule, "dxf") + if inline_dxf is not None: + dxf = _dxf(inline_dxf) + if dxf: + entry["dxf"] = dxf + params = [ + _dump(c) for c in rule if _ln(c.tag) in ("colorScale", "dataBar", "iconSet") + ] + if params: + entry["params"] = params + return entry + + +def _conditional_formats( + main: list[Any], ext: list[Any], styles: _Styles +) -> dict[str, Any]: + ext_rules: dict[str, tuple[Any, str]] = {} + unlinked: list[tuple[Any, str]] = [] + for cf in ext: + sq = _kid(cf, "sqref") + sqref = sq.text if sq is not None else "" + for rule in _kids(cf, "cfRule"): + rid = rule.get("id") + if rid: + ext_rules[rid] = (rule, sqref) + unlinked.append((rule, sqref)) + linked: set[str] = set() + collected: list[tuple[int, int, dict[str, Any]]] = [] + order = 0 + for cf in main: + sqref = cf.get("sqref", "") + for rule in _kids(cf, "cfRule"): + entry = _cf_rule(rule, sqref, styles) + for ext_el in _kids(_kid(rule, "extLst"), "ext"): + ident = _kid(ext_el, "id") + if ident is not None and ident.text in ext_rules: + linked.add(ident.text) + ext_rule = ext_rules[ident.text][0] + entry["x14"] = [_dump(c) for c in ext_rule if _ln(c.tag) != "dxf"] + priority = _int(rule.get("priority")) + collected.append( + (priority if priority is not None else 1 << 30, order, entry) + ) + order += 1 + for rule, sqref in unlinked: + if rule.get("id") in linked: + continue + entry = _cf_rule(rule, sqref, styles) + priority = _int(rule.get("priority")) + collected.append((priority if priority is not None else 1 << 30, order, entry)) + order += 1 + out: dict[str, Any] = {} + for rank, (_, _, entry) in enumerate( + sorted(collected, key=lambda x: (x[0], x[1])), 1 + ): + entry["rank"] = rank + out[_key(entry)] = entry + return dict(sorted(out.items())) + + +# --------------------------------------------------------------------------- +# Drawings: images and charts +# --------------------------------------------------------------------------- + + +def _choose(alt: Any) -> list[Any]: + """Children of the first Choice (else Fallback) of mc:AlternateContent.""" + choice = _kid(alt, "Choice") + if choice is None: + choice = _kid(alt, "Fallback") + return list(choice) if choice is not None else [] + + +def _anchors(root: Any) -> list[Any]: + out: list[Any] = [] + for child in root: + tag = _ln(child.tag) + if tag == "AlternateContent": + out.extend(_anchors(_choose_el(child))) + elif tag in ("twoCellAnchor", "oneCellAnchor", "absoluteAnchor"): + out.append(child) + return out + + +def _choose_el(alt: Any) -> Any: + holder = ET.Element("holder") + holder.extend(_choose(alt)) + return holder + + +def _walk_objects(el: Any) -> list[tuple[str, Any]]: + """('pic', blip) and ('chart', chart ref element) in document order.""" + found: list[tuple[str, Any]] = [] + for c in el: + tag = _ln(c.tag) + if tag == "AlternateContent": + found.extend(_walk_objects(_choose_el(c))) + elif tag == "pic": + blip = next((d for d in c.iter() if _ln(d.tag) == "blip"), None) + if blip is not None: + found.append(("pic", blip)) + elif tag == "graphicFrame": + data = next((d for d in c.iter() if _ln(d.tag) == "graphicData"), None) + for d in data if data is not None else (): + if _ln(d.tag) == "chart": + found.append(("chart", d)) + elif tag == "grpSp": + found.extend(_walk_objects(c)) + return found + + +def _anchor_name(anchor: Any) -> str: + frm = _kid(anchor, "from") + if frm is None: + return "absolute" + col = ( + _int((_kid(frm, "col").text if _kid(frm, "col") is not None else None), 0) or 0 + ) + row = ( + _int((_kid(frm, "row").text if _kid(frm, "row") is not None else None), 0) or 0 + ) + return f"{_col_name(col + 1)}{row + 1}" + + +def _image_token(pkg: _Package, source: str, rid: str | None) -> str | None: + rel = pkg.deref(source, rid) + if rel is None: + return None + if rel.external: + return f"external:{rel.target}" + data = pkg.parts.get(rel.target) + return hashlib.sha256(data).hexdigest() if data is not None else None + + +def _drawings( + pkg: _Package, part: str, root: Any, name: str, model: dict[str, Any] +) -> None: + images: dict[str, int] = {} + charts: dict[str, Any] = {} + is_chartsheet = _ln(root.tag) == "chartsheet" + picture = _kid(root, "picture") + if picture is not None: + token = _image_token(pkg, part, _rel_attr(picture, "id")) + if token: + images[f"background|{token}"] = images.get(f"background|{token}", 0) + 1 + drawing = _kid(root, "drawing") + dparts = [] + if drawing is not None: + rel = pkg.deref(part, _rel_attr(drawing, "id")) + if rel and not rel.external and rel.target in pkg.parts: + dparts.append(rel.target) + for dpart in dparts: + droot = pkg.xml(dpart) + for anchor in _anchors(droot): + where = "sheet" if is_chartsheet else _anchor_name(anchor) + for kind, el in _walk_objects(anchor): + if kind == "pic": + token = _image_token( + pkg, dpart, _rel_attr(el, "embed") or _rel_attr(el, "link") + ) + if token: + key = f"{where}|{token}" + images[key] = images.get(key, 0) + 1 + else: + rel = pkg.deref(dpart, _rel_attr(el, "id")) + if rel is None or rel.external or rel.target not in pkg.parts: + continue + key = where + n = 2 + while key in charts: + key = f"{where}#{n}" + n += 1 + charts[key] = _chart(pkg.xml(rel.target)) + model["images"][name] = dict(sorted(images.items())) + model["charts"][name] = charts + + +_STRING_FORMULA_RE = re.compile(r'^=?\s*"((?:[^"]|"")*)"$') + + +def _ref_or_literal(el: Any) -> Any: + if el is None: + return None + for d in el.iter(): + if _ln(d.tag) == "f" and d.text: + literal = _STRING_FORMULA_RE.match(d.text.strip()) + if literal: + return {"literal": [literal.group(1).replace('""', '"')]} + return {"ref": _chart_ref(d.text)} + values = [_unescape(v.text or "") for v in el.iter() if _ln(v.tag) == "v"] + if values: + return {"literal": values} + return None + + +def _chart(root: Any) -> dict[str, Any]: + ns = root.tag[1:].split("}", 1)[0] if root.tag.startswith("{") else "" + if "chartex" in ns: + layouts = [s.get("layoutId") for s in root.iter() if _ln(s.tag) == "series"] + return {"format": "chartex", "types": layouts} + chart = _kid(root, "chart") + out: dict[str, Any] = {} + title = _kid(chart, "title") + if title is not None: + tx = _kid(title, "tx") + texts = [ + t.text or "" + for t in (tx.iter() if tx is not None else ()) + if _ln(t.tag) == "t" + ] + if texts: + out["title"] = {"text": "".join(texts)} + else: + out["title"] = _ref_or_literal(tx) or {"auto": True} + plot = _kid(chart, "plotArea") + types: list[str] = [] + series: list[tuple[int, int, dict[str, Any]]] = [] + seq = 0 + for p in plot if plot is not None else (): + tag = _ln(p.tag) + if not tag.endswith("Chart"): + continue + bar_dir = _attr(_kid(p, "barDir"), "val") + ptype = ( + f"{tag}/{bar_dir or 'col'}" if tag in ("barChart", "bar3DChart") else tag + ) + types.append(ptype) + for ser in _kids(p, "ser"): + entry: dict[str, Any] = {"plot": ptype} + for field, child in ( + ("name", "tx"), + ("values", "val"), + ("categories", "cat"), + ("x", "xVal"), + ("y", "yVal"), + ("bubble_sizes", "bubbleSize"), + ): + value = _ref_or_literal(_kid(ser, child)) + if value is not None: + entry[field] = value + order = _int(_attr(_kid(ser, "order"), "val"), seq) + series.append((order if order is not None else seq, seq, entry)) + seq += 1 + out["types"] = types + out["series"] = [e for _, _, e in sorted(series, key=lambda x: (x[0], x[1]))] + return out + + +# --------------------------------------------------------------------------- +# Comparison +# --------------------------------------------------------------------------- + + +def _expand_styles(model: dict[str, Any]) -> dict[str, Any]: + """Replace content-addressed style keys with the style dicts they name.""" + styles = model.get("cell_styles", {}) + table = styles.get("table", {}) + + def resolve(key: Any) -> Any: + return table.get(key, key) if isinstance(key, str) else key + + out = dict(model) + out["cell_styles"] = { + "default": resolve(styles.get("default")), + "sheets": { + sheet: {addr: resolve(k) for addr, k in cells.items()} + for sheet, cells in styles.get("sheets", {}).items() + }, + } + for feature in ("columns", "rows"): + out[feature] = { + sheet: { + span: ( + {**props, "style": resolve(props["style"])} + if "style" in props + else props + ) + for span, props in entries.items() + } + for sheet, entries in model.get(feature, {}).items() + } + return out + + +def _escape(key: str) -> str: + return key.replace("~", "~0").replace("/", "~1") + + +# Shared presentation tolerances (see the module docstring). Each pattern is +# matched against the full JSON Pointer of a numeric leaf. +_LENGTH_TOLERANCES = ( + # column width in characters: 1 character = 7 px = 5.25 pt + (re.compile(r"^/columns/[^/]+/[^/]+/width$"), 0.5 / 5.25), + # row height in points + (re.compile(r"^/rows/[^/]+/[^/]+/height$"), 0.5), + # page and header/footer margins in inches + (re.compile(r"^/page_setup/[^/]+/margins/[^/]+$"), 0.5 / 72), +) +_RELATIVE_FLOAT_PATHS = re.compile(r"/fill/gradient/") +_RELATIVE_TOLERANCE = 1e-9 +# A color modifier on a -1..1 scale changes an 8-bit channel by at most +# 255 * delta * 2 levels; below 1/510 it cannot move a channel a full level. +_MODIFIER_TOLERANCE = 1 / 510 +_TINT_RE = re.compile(r"^(.*)~tint:([^~]+)$") +_CONTENT_KEY_RE = re.compile(r"^[0-9a-f]{16}$") + + +def _close(x: float, y: float) -> bool: + return abs(x - y) <= _RELATIVE_TOLERANCE * max(abs(x), abs(y)) + + +def _split_tint(color: str) -> tuple[str, float | None]: + """Color token -> (base, tint); an absent tint is 0, a bad one None.""" + m = _TINT_RE.match(color) + if not m: + return color, 0.0 + try: + return m.group(1), float(m.group(2)) + except ValueError: + return m.group(1), None + + +def _leaf_equal(x: Any, y: Any, path: str) -> bool: + if type(x) is type(y) and x == y: + return True + numbers = (int, float) + if ( + isinstance(x, numbers) + and isinstance(y, numbers) + and not isinstance(x, bool) + and not isinstance(y, bool) + ): + for pattern, tolerance in _LENGTH_TOLERANCES: + if pattern.match(path): + return abs(x - y) <= tolerance + return bool(_RELATIVE_FLOAT_PATHS.search(path)) and _close(x, y) + if isinstance(x, str) and isinstance(y, str) and ("~tint:" in x or "~tint:" in y): + bx, tx = _split_tint(x) + by, ty = _split_tint(y) + return ( + bx == by + and tx is not None + and ty is not None + and abs(tx - ty) <= _MODIFIER_TOLERANCE + ) + return False + + +def _pair_content_keys( + x: dict[str, Any], y: dict[str, Any], path: str, feature: str +) -> set[str]: + """Content-addressed keys present on one side only whose values are equal + under the presentation tolerances (the hash itself is exact).""" + only_x = [k for k in x if k not in y and _CONTENT_KEY_RE.match(str(k))] + only_y = [k for k in y if k not in x and _CONTENT_KEY_RE.match(str(k))] + paired: set[str] = set() + for kx in only_x: + for ky in only_y: + if ky in paired: + continue + probe: list[dict[str, Any]] = [] + _diff(x[kx], y[ky], f"{path}/{kx}", feature, probe) + if not probe: + paired.update((kx, ky)) + break + return paired + + +def _align_runs( + x: dict[str, Any], y: dict[str, Any] +) -> tuple[dict[str, Any], dict[str, Any]]: + """Re-key two column-run maps onto their common partition, so runs split + differently (e.g. by widths equal within tolerance) compare per column.""" + + def spans(d: dict[str, Any]) -> list[tuple[int, int, Any]]: + out = [] + for key, props in d.items(): + m = _SPAN_RE.match(str(key)) + if m: + out.append((_col_num(m.group(1)), _col_num(m.group(2)), props)) + return out + + sx, sy = spans(x), spans(y) + cuts = sorted({lo for lo, _, _ in sx + sy} | {hi + 1 for _, hi, _ in sx + sy}) + + def rekey(d: dict[str, Any], runs: list[tuple[int, int, Any]]) -> dict[str, Any]: + out = {k: v for k, v in d.items() if not _SPAN_RE.match(str(k))} + for lo, hi, props in runs: + inside = [c for c in cuts if lo <= c <= hi + 1] + for s, e in itertools.pairwise(inside): + out[f"{_col_name(s)}:{_col_name(e - 1)}"] = props + return out + + return rekey(x, sx), rekey(y, sy) + + +_SPAN_RE = re.compile(r"^([A-Z]{1,3}):([A-Z]{1,3})$") + + +def _diff(x: Any, y: Any, path: str, feature: str, out: list[dict[str, Any]]) -> None: + if isinstance(x, dict) and isinstance(y, dict): + paired = _pair_content_keys(x, y, path, feature) + for key in sorted(set(x) | set(y), key=str): + if key in paired: + continue + sub = f"{path}/{_escape(str(key))}" + if key not in y: + out.append( + { + "feature": feature, + "path": sub, + "kind": "missing", + "before": x[key], + "after": None, + } + ) + elif key not in x: + out.append( + { + "feature": feature, + "path": sub, + "kind": "added", + "before": None, + "after": y[key], + } + ) + else: + _diff(x[key], y[key], sub, feature, out) + return + if isinstance(x, list) and isinstance(y, list): + for i in range(max(len(x), len(y))): + sub = f"{path}/{i}" + if i >= len(y): + out.append( + { + "feature": feature, + "path": sub, + "kind": "missing", + "before": x[i], + "after": None, + } + ) + elif i >= len(x): + out.append( + { + "feature": feature, + "path": sub, + "kind": "added", + "before": None, + "after": y[i], + } + ) + else: + _diff(x[i], y[i], sub, feature, out) + return + if not _leaf_equal(x, y, path): + out.append( + { + "feature": feature, + "path": path, + "kind": "changed", + "before": x, + "after": y, + } + ) + + +def compare(before: dict[str, Any], after: dict[str, Any]) -> list[dict[str, Any]]: + b, a = _expand_styles(before), _expand_styles(after) + diffs: list[dict[str, Any]] = [] + for feature in FEATURES: + path = f"/{feature}" + if feature not in a and feature in b: + diffs.append( + { + "feature": feature, + "path": path, + "kind": "missing", + "before": b[feature], + "after": None, + } + ) + elif feature not in b and feature in a: + diffs.append( + { + "feature": feature, + "path": path, + "kind": "added", + "before": None, + "after": a[feature], + } + ) + elif feature in a: + x, y = b[feature], a[feature] + if feature == "columns": + x, y = dict(x), dict(y) + for sheet in set(x) & set(y): + x[sheet], y[sheet] = _align_runs(x[sheet], y[sheet]) + _diff(x, y, path, feature, diffs) + return diffs diff --git a/src/excelbench/harness/external_oracles.py b/src/excelbench/harness/external_oracles.py index 6f7d535..1802e22 100644 --- a/src/excelbench/harness/external_oracles.py +++ b/src/excelbench/harness/external_oracles.py @@ -14,6 +14,22 @@ JSONDict = dict[str, Any] +#: Env var naming a Docker context (for example ``pc``) on which the Java/Go +#: write-only helpers run as containers instead of local builds. +ORACLE_DOCKER_CONTEXT_ENV = "EXCELBENCH_ORACLE_DOCKER_CONTEXT" + +#: Images built from ``tools/external-oracles//Dockerfile``; see +#: ``tools/external-oracles/remote/README.md``. +ORACLE_DOCKER_IMAGES: Mapping[str, str] = { + "apache-poi": "excelbench-poi-oracle:5.5.1", + "excelize": "excelbench-excelize-oracle:2.10.1", +} + +#: Per-request timeout floor for helpers reached through a remote Docker +#: context. Container start-up on a shared build host can exceed the local +#: helper timeouts; a transport stall must not be recorded as a library failure. +ORACLE_DOCKER_TIMEOUT_FLOOR_SECONDS = 900.0 + @dataclass(frozen=True) class ExternalOracleTool: @@ -32,6 +48,8 @@ class ExternalOracleTool: into this repository. required_paths: Optional files/directories that must exist before the helper is considered available. + min_timeout_seconds: Lower bound applied to every request timeout, + used for transports (remote containers) slower than a local run. """ name: str @@ -42,6 +60,7 @@ class ExternalOracleTool: env: Mapping[str, str] = field(default_factory=dict) cwd: Path | None = None required_paths: tuple[Path, ...] = () + min_timeout_seconds: float = 0.0 def resolve_executable(self) -> str | None: """Resolve the command executable without running it.""" @@ -128,6 +147,8 @@ def external_oracle_catalog( """ excelize_command: tuple[str, ...] = ("excelbench-excelize-oracle",) excelize_cwd = None + excelize_required_paths: tuple[Path, ...] = () + remote_timeout_floor = 0.0 if repo_root is not None: excelize_command = ("go", "run", ".") excelize_cwd = repo_root / "tools" / "external-oracles" / "excelize" @@ -210,6 +231,23 @@ def external_oracle_catalog( zavora_command = ("cargo", "run", "--quiet") zavora_required_paths = (zavora_cwd / "Cargo.toml",) + docker_context = os.environ.get(ORACLE_DOCKER_CONTEXT_ENV) + if repo_root is not None and docker_context: + wrapper = ( + repo_root / "tools" / "external-oracles" / "remote" / "docker_oracle.py" + ) + excelize_command = _docker_oracle_command( + wrapper, docker_context, ORACLE_DOCKER_IMAGES["excelize"] + ) + excelize_cwd = None + excelize_required_paths = (wrapper,) + apache_poi_command = _docker_oracle_command( + wrapper, docker_context, ORACLE_DOCKER_IMAGES["apache-poi"] + ) + apache_poi_cwd = None + apache_poi_required_paths = (wrapper,) + remote_timeout_floor = ORACLE_DOCKER_TIMEOUT_FLOOR_SECONDS + return { "excelize": ExternalOracleTool( name="excelize", @@ -218,6 +256,8 @@ def external_oracle_catalog( homepage="https://github.com/qax-os/excelize", capabilities=frozenset({"read", "write", "charts", "pivots", "slicers"}), cwd=excelize_cwd, + required_paths=excelize_required_paths, + min_timeout_seconds=remote_timeout_floor, ), "libreoffice": ExternalOracleTool( name="libreoffice", @@ -244,6 +284,7 @@ def external_oracle_catalog( ), cwd=apache_poi_cwd, required_paths=apache_poi_required_paths, + min_timeout_seconds=remote_timeout_floor, ), "exceljs": ExternalOracleTool( name="exceljs", @@ -294,6 +335,11 @@ def external_oracle_catalog( } +def _docker_oracle_command(wrapper: Path, context: str, image: str) -> tuple[str, ...]: + """Command that runs a helper image on a Docker context via the stdin/stdout wrapper.""" + return (sys.executable, str(wrapper), "--context", context, "--image", image) + + def run_external_oracle( tool: ExternalOracleTool, request: ExternalOracleRequest, @@ -319,6 +365,7 @@ def run_external_oracle( payload={}, notes=f"External oracle helper not found: {tool.command[0] if tool.command else ''}", ) + timeout_seconds = max(timeout_seconds, tool.min_timeout_seconds) env = os.environ.copy() env.update(tool.env) diff --git a/src/excelbench/harness/mutation.py b/src/excelbench/harness/mutation.py index 7f65826..a4a7f7e 100644 --- a/src/excelbench/harness/mutation.py +++ b/src/excelbench/harness/mutation.py @@ -1,7 +1,8 @@ -"""Isolated mutation timing and OOXML preservation scoring.""" +"""Isolated mutation timing and content-model preservation scoring.""" from __future__ import annotations +import copy import hashlib import json import os @@ -17,9 +18,13 @@ from typing import Any from zipfile import ZipFile -import openpyxl - -from excelbench.modifiable import ModifiableEngine, Mutation, modifiable_engines +from excelbench.harness import content_model_xlsx as content_model +from excelbench.modifiable import ( + ModifiableEngine, + Mutation, + _mutation_target, + modifiable_engines, +) _WORKSHEET_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" _RELATIONSHIPS_NS = "http://schemas.openxmlformats.org/package/2006/relationships" @@ -47,6 +52,27 @@ "pane", "drawing", ) +CUSTOM_XML_FEATURE = "custom_xml" +SCORED_FEATURES: tuple[str, ...] = (*content_model.FEATURES, CUSTOM_XML_FEATURE) +_SAMPLE_SIZE = 10 +_ROW_SCORE_FIELDS = ( + "preserved", + "edits_applied", + "feature_preservation", + "features_present", + "features_changed", +) +_ROW_DETAIL_FIELDS = ("edits", "sample", "integrity", "diagnostics") + +_REPO_ROOT = Path(__file__).resolve().parents[3] + + +def _portable_error(error: Exception) -> str: + """Error text for published results: repository and home paths become placeholders.""" + text = f"{type(error).__name__}: {error}" + for root, placeholder in ((_REPO_ROOT, ""), (Path.home(), "~")): + text = text.replace(str(root), placeholder) + return text def _sha256_file(path: Path) -> str: @@ -61,11 +87,7 @@ def _sha256_file(path: Path) -> str: 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("/") - } + return {name: archive.read(name) for name in archive.namelist() if not name.endswith("/")} def _xml_has_element(xml: bytes, element: str) -> bool: @@ -149,10 +171,7 @@ def _missing_content_types(parts: dict[str, bytes]) -> list[str]: 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) - } + 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": @@ -163,51 +182,244 @@ def _missing_content_types(parts: dict[str, bytes]) -> list[str]: 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 +def _canonical_xml(data: bytes) -> str: + """Return C14N 2.0 text that ignores encoding, prefixes, attribute order and padding.""" + try: + return ET.canonicalize( + xml_data=data.decode("utf-8-sig"), + strip_text=True, + rewrite_prefixes=True, + ) + except (ET.ParseError, UnicodeDecodeError): + return f"unparsable:{hashlib.sha256(data).hexdigest()}" + + +def _relationship_sources(package: content_model._Package) -> list[str]: + """Return every part (``""`` for the package root) that owns a ``.rels`` part.""" + sources: list[str] = [] + for key in package.parts: + directory, base = posixpath.split(key) + if posixpath.basename(directory) != "_rels" or not base.endswith(".rels"): + continue + sources.append(posixpath.join(posixpath.dirname(directory), base[: -len(".rels")])) + return sorted(sources) + + +def _custom_xml_items(path: Path) -> dict[str, dict[str, Any]]: + """Model custom XML data items independent of part names and relationship ids. + + Items are found by relationship type from any owning part. Each item is its + canonical XML plus the datastore item id and schema references from its + properties part; the result is a multiset keyed by a hash of that record. + """ + package = content_model._Package(path) + targets = sorted( + { + target + for source in _relationship_sources(package) + for target in package.targets(source, "customXml") + } ) + items: dict[str, dict[str, Any]] = {} + for target in targets: + record: dict[str, Any] = {"xml": _canonical_xml(package.parts[target])} + for props_part in package.targets(target, "customXmlProps")[:1]: + try: + props = ET.fromstring(package.parts[props_part]) + except ET.ParseError: + record["props"] = "unparsable" + continue + item_id = next( + (value for name, value in props.attrib.items() if name.endswith("itemID")), + None, + ) + record["item_id"] = item_id.upper() if item_id else None + record["schemas"] = sorted( + element.get("uri", "") + for element in props.iter() + if isinstance(element.tag, str) and element.tag.endswith("schemaRef") + ) + key = hashlib.sha256(json.dumps(record, sort_keys=True).encode()).hexdigest()[:16] + if key in items: + items[key]["count"] += 1 + else: + items[key] = {**record, "count": 1} + return items + + +def _compare_custom_xml( + before: dict[str, dict[str, Any]], after: dict[str, dict[str, Any]] +) -> list[dict[str, Any]]: + """Diff two custom XML multisets in the content model's diff-record shape.""" + diffs: list[dict[str, Any]] = [] + for key in sorted(set(before) | set(after)): + old, new = before.get(key), after.get(key) + if old is not None and new is not None and old["count"] == new["count"]: + continue + kind = "missing" if new is None else "added" if old is None else "changed" + diffs.append( + { + "feature": CUSTOM_XML_FEATURE, + "path": f"/{CUSTOM_XML_FEATURE}/{key}", + "kind": kind, + "before": old, + "after": new, + } + ) + return diffs + + +def _cell_entry(value: Any) -> dict[str, Any] | None: + """Return the content-model cell entry a correct engine writes for ``value``.""" + if value is None: + return None + if isinstance(value, bool): + return {"type": "b", "value": value} + if isinstance(value, int | float): + return {"type": "n", "value": float(value)} + if isinstance(value, str): + return {"type": "s", "value": value} + raise ValueError(f"Unsupported mutation value type: {type(value).__name__}") + + +def _edit_targets( + model: dict[str, Any], mutations: list[Mutation] +) -> list[tuple[str, str, dict[str, Any] | None]]: + """Resolve declared edits to ``(sheet, canonical address, expected cell entry)``.""" + targets: list[tuple[str, str, dict[str, Any] | None]] = [] + for mutation in mutations: + sheet, cell, value = _mutation_target(mutation) + if sheet not in model["cells"]: + raise ValueError(f"Mutation sheet {sheet!r} is not a worksheet in the template") + targets.append((sheet, cell.replace("$", "").upper(), _cell_entry(value))) + return targets + + +def _apply_edits( + model: dict[str, Any], targets: list[tuple[str, str, dict[str, Any] | None]] +) -> dict[str, Any]: + """Return the model a correct engine produces: each edited cell holds its new + constant value (replacing any formula there) and nothing else changes.""" + expected = copy.deepcopy(model) + for sheet, address, entry in targets: + cells = expected["cells"][sheet] + if entry is None: + cells.pop(address, None) + else: + cells[address] = entry + expected["formulas"][sheet].pop(address, None) + return expected + + +def _without_formula_results( + model: dict[str, Any], formula_cells: set[tuple[str, str]] +) -> dict[str, Any]: + """Drop cached formula results, which are recalculation state after an edit.""" + projected = dict(model) + projected["cells"] = { + sheet: { + address: entry + for address, entry in cells.items() + if (sheet, address) not in formula_cells + } + for sheet, cells in model["cells"].items() + } + return projected + +def _formula_cells(*models: dict[str, Any]) -> set[tuple[str, str]]: + """Return every ``(sheet, address)`` holding a formula in any of ``models``.""" 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, + (sheet, address) + for model in models + for sheet, formulas in model["formulas"].items() + for address in formulas + } + + +def _has_content(value: Any) -> bool: + """Return whether a model value records anything beyond empty/false/zero defaults.""" + if isinstance(value, dict): + return any(_has_content(item) for item in value.values()) + if isinstance(value, list): + return any(_has_content(item) for item in value) + return bool(value) + + +def score_preservation(template: Path, output: Path, mutations: list[Mutation]) -> dict[str, Any]: + """Score a mutation output by observable workbook content, not package layout. + + The expected result is the template's content model with the declared edits + applied the way a correct engine applies them. Any other content difference + in the output is unexpected. Part names, relationship ids, XML serialization + and document metadata are not content, so an equivalent re-serialization + scores the same as a byte copy. Cached results of formula cells are + recalculation state (an engine may keep, drop, or recompute them after an + edit) and are excluded; formula text is compared under ``formulas``. + """ + template_model = content_model.extract(template) + output_model = content_model.extract(output) + targets = _edit_targets(template_model, mutations) + expected_model = _apply_edits(template_model, targets) + + formula_cells = _formula_cells(expected_model, output_model) + template_custom_xml = _custom_xml_items(template) + unexpected = content_model.compare( + _without_formula_results(expected_model, formula_cells), + _without_formula_results(output_model, formula_cells), + ) + _compare_custom_xml(template_custom_xml, _custom_xml_items(output)) + + edits = [] + for sheet, address, entry in targets: + actual = output_model["cells"].get(sheet, {}).get(address) + actual_value = ( + None if actual is None else {"type": actual["type"], "value": actual["value"]} + ) + edits.append( + { + "sheet": sheet, + "cell": address, + "expected": entry, + "actual": actual_value, + "applied": actual_value == entry, + } + ) + edits_applied = all(edit["applied"] for edit in edits) + + template_content = {**template_model, CUSTOM_XML_FEATURE: template_custom_xml} + features_present = [ + feature for feature in SCORED_FEATURES if _has_content(template_content[feature]) + ] + changed_counts: dict[str, int] = {} + for diff in unexpected: + changed_counts[diff["feature"]] = changed_counts.get(diff["feature"], 0) + 1 + features_changed = { + feature: changed_counts[feature] for feature in SCORED_FEATURES if feature in changed_counts + } + kept = [feature for feature in features_present if feature not in features_changed] + + output_parts = _package_parts(output) + original_parts = _package_parts(template) + return { + "preserved": not unexpected and edits_applied, + "edits_applied": edits_applied, + "edits": edits, + "features_present": features_present, + "features_changed": features_changed, + "feature_preservation": f"{len(kept)}/{len(features_present)}", + "sample": unexpected[:_SAMPLE_SIZE], + "integrity": { + "dangling_rels": _dangling_relationships(output_parts), + "missing_content_types": _missing_content_types(output_parts), + }, + "diagnostics": { + "lost_parts": sorted(set(original_parts) - set(output_parts)), + "added_parts": sorted(set(output_parts) - set(original_parts)), + "element_changes": [ + entry + for entry in _element_checklist(original_parts, output_parts) + if entry["present_in_original"] != entry["present_in_output"] + ], }, } @@ -242,16 +454,10 @@ def _run_subprocess_mutation( 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" - ) + 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()}" - ) + raise RuntimeError(f"Unable to parse /usr/bin/time -l output: {completed.stderr.strip()}") return elapsed_seconds * 1000, peak_rss_kb @@ -262,26 +468,34 @@ def _mutations_for_engine(manifest: dict[str, Any], engine_name: str) -> list[Mu 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 _engine_row( + *, + available: bool, + status: str, + wall_times: list[float] | None = None, + peak_rss_values: list[float] | None = None, + scored: dict[str, Any] | None = None, + details: dict[str, Any] | None = None, +) -> dict[str, Any]: + """Build one engine's result row; unscored rows carry ``None`` score fields.""" + row: dict[str, Any] = { + "available": available, + "status": status, + "wall_ms_median": round(statistics.median(wall_times), 3) if wall_times else None, + "peak_rss_kb_median": round(statistics.median(peak_rss_values), 3) + if peak_rss_values + else None, + } + for field in _ROW_SCORE_FIELDS: + row[field] = scored[field] if scored is not None else None + row["details"] = dict(details or {}) + if scored is not None: + row["details"].update({field: scored[field] for field in _ROW_DETAIL_FIELDS}) + return row -def run_mutation_suite( - template: Path, output_dir: Path, repeats: int = 3 -) -> dict[str, Any]: - """Benchmark isolated surgical mutations and score package preservation.""" +def run_mutation_suite(template: Path, output_dir: Path, repeats: int = 3) -> dict[str, Any]: + """Benchmark isolated surgical mutations and score content preservation.""" if repeats < 1: raise ValueError("repeats must be at least 1") template = Path(template) @@ -295,14 +509,11 @@ def run_mutation_suite( 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"}, - } + engine_results[engine.name] = _engine_row( + available=False, + status="unavailable", + details={"reason": "engine unavailable"}, + ) continue engine_dir = output_dir / engine.name @@ -325,34 +536,20 @@ def run_mutation_suite( 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, - } + scored = score_preservation(template, final_output, mutations) + engine_results[engine.name] = _engine_row( + available=True, + status="passed" if scored["edits_applied"] else "edits-missing", + wall_times=wall_times, + peak_rss_values=peak_rss_values, + scored=scored, + ) 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}"}, - } - + engine_results[engine.name] = _engine_row( + available=True, + status="failed", + details={"error": _portable_error(error)}, + ) return { "metadata": { "template_sha256": _sha256_file(template), diff --git a/src/excelbench/modifiable.py b/src/excelbench/modifiable.py index da78967..5a3f07b 100644 --- a/src/excelbench/modifiable.py +++ b/src/excelbench/modifiable.py @@ -199,6 +199,62 @@ def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> Non intermediate_path.unlink(missing_ok=True) +class _JsonHelperEngine: + """Workbook mutation through a JSON-model adapter helper (Node, LibreOffice).""" + + name = "" + adapter_module = "" + adapter_class = "" + + def _adapter(self) -> Any: + import importlib + + module = importlib.import_module(self.adapter_module) + return getattr(module, self.adapter_class) + + def available(self) -> bool: + """Return whether the helper runtime and dependencies are installed.""" + return bool(self._adapter().is_available()) + + def mutate(self, template: Path, output: Path, mutations: list[Mutation]) -> None: + """Open the template with the library, set values, and save the output.""" + for mutation in mutations: + _mutation_target(mutation) + self._adapter().mutate_file(template, output, mutations) + + +class SheetjsEngine(_JsonHelperEngine): + """SheetJS CE: parse the whole package, set cells, write a new package.""" + + name = "sheetjs" + adapter_module = "excelbench.harness.adapters.sheetjs_adapter" + adapter_class = "SheetjsAdapter" + + +class ExceljsEngine(_JsonHelperEngine): + """ExcelJS: load the workbook model, set cells, write a new package.""" + + name = "exceljs" + adapter_module = "excelbench.harness.adapters.exceljs_adapter" + adapter_class = "ExceljsAdapter" + + +class LibreofficeEngine(_JsonHelperEngine): + """LibreOffice Calc: import via the OOXML filter, set cells, export again.""" + + name = "libreoffice" + adapter_module = "excelbench.harness.adapters.libreoffice_adapter" + adapter_class = "LibreofficeAdapter" + + def modifiable_engines() -> list[ModifiableEngine]: """Return the fixed engine registry used by the mutation suite.""" - return [OpenpyxlEngine(), WolfxlEngine(), AsposeFossEngine(), ZavoraEngine()] + return [ + OpenpyxlEngine(), + WolfxlEngine(), + AsposeFossEngine(), + ZavoraEngine(), + SheetjsEngine(), + ExceljsEngine(), + LibreofficeEngine(), + ] diff --git a/src/excelbench/results/html_dashboard.py b/src/excelbench/results/html_dashboard.py index b19159e..499b46e 100644 --- a/src/excelbench/results/html_dashboard.py +++ b/src/excelbench/results/html_dashboard.py @@ -1475,10 +1475,10 @@ def _section_overview(fidelity: dict[str, Any], perf: dict[str, Any] | None) -> f'' diff --git a/src/excelbench/results/mutation_renderer.py b/src/excelbench/results/mutation_renderer.py index 9c3c8ea..f6f6c51 100644 --- a/src/excelbench/results/mutation_renderer.py +++ b/src/excelbench/results/mutation_renderer.py @@ -14,30 +14,60 @@ def _format_number(value: object, suffix: str = "") -> str: return "—" -def _verdict(result: dict[str, Any]) -> str: - """Return a concise status label for an engine result.""" +def mutation_verdict(result: dict[str, Any]) -> str: + """Return the verdict for one engine row. + + Preserved / Changed / Edits missing / Failed, plus Unavailable for + engines that were not run. + """ 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: + if not result.get("edits_applied"): + return "Edits missing" + if result.get("preserved"): return "Preserved" - return "Loss detected" + changed = result.get("features_changed") or {} + return "Changed " + ", ".join(changed) + + +def _changed_text(result: dict[str, Any]) -> str: + """Summarize unexpected differences per feature for a Markdown cell.""" + changed = result.get("features_changed") + if not isinstance(changed, dict): + return "—" + if not changed: + return "none" + return ", ".join(f"{feature} ({count})" for feature, count in changed.items()) + + +def _integrity_text(result: dict[str, Any]) -> str: + """Summarize package integrity issues (unscored) for a Markdown cell.""" + integrity = result.get("details", {}).get("integrity") + if not isinstance(integrity, dict): + return "—" + issues = len(integrity.get("dangling_rels", [])) + len( + integrity.get("missing_content_types", []) + ) + return "ok" if issues == 0 else f"{issues} issue(s)" 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) + engine_results = { + name: {**result, "verdict": mutation_verdict(result)} + for name, result in results.get("engines", {}).items() + } + persisted = {**results, "engines": engine_results} (output_dir / "results.json").write_text( - json.dumps(results, indent=2, sort_keys=True) + "\n", encoding="utf-8" + json.dumps(persisted, indent=2, sort_keys=True) + "\n", encoding="utf-8" ) metadata = results.get("metadata", {}) - engine_results = results.get("engines", {}) lines = [ "# ExcelBench Mutation Results", "", @@ -47,20 +77,24 @@ def render_mutation_report(results: dict[str, Any], output_dir: Path) -> None: "", "## Comparison", "", - "| Engine | Wall ms | Peak RSS KB | Preservation score | Lost parts | Verdict |", - "|--------|---------|-------------|--------------------|------------|---------|", + ( + "| Engine | Wall ms | Peak RSS KB | Features preserved | Unexpected changes " + "| Edits applied | Integrity | 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 "—" + edits_applied = result.get("edits_applied") + edits_text = "—" if edits_applied is None else ("yes" if edits_applied else "no") 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)} |" + f"{_format_number(result.get('peak_rss_kb_median'))} | " + f"{result.get('feature_preservation') or '—'} | {_changed_text(result)} | " + f"{edits_text} | {_integrity_text(result)} | {result['verdict']} |" ) lines.extend( [ @@ -72,8 +106,15 @@ def render_mutation_report(results: dict[str, Any], output_dir: Path) -> None: "with macOS `/usr/bin/time -l`." ), ( - "Preservation compares each output package against the original template. " - "It does not measure formula recalculation or rendering." + "Preservation compares the output's workbook content model against the " + "template's model with the two declared cell edits applied. Part names, " + "relationship ids, XML serialization and document metadata are not " + "content, so an equivalent rewrite scores the same as a byte copy. " + "Cached results of formula cells are recalculation state and are not " + "compared; formula text is. Features preserved counts template features " + "with no unexpected difference. Integrity (dangling relationships, parts " + "without a content type) is reported separately and is not scored. " + "This does not measure formula recalculation or rendering." ), "", ] diff --git a/src/excelbench/results/renderer.py b/src/excelbench/results/renderer.py index 0317787..2053071 100644 --- a/src/excelbench/results/renderer.py +++ b/src/excelbench/results/renderer.py @@ -483,7 +483,7 @@ def _lib_summary(lib: str, green: int, total: int) -> str: """One-line summary for tier list.""" summaries: dict[str, str] = { "openpyxl": "Reference adapter — full read + write fidelity", - "wolfxl": "Hybrid Rust+Python — near-full fidelity at 3-9x throughput", + "wolfxl": "Hybrid Rust+Python: openpyxl-compatible API with patch-mode modify", "rust_xlsxwriter": "Rust write backend — used internally by WolfXL", "xlsxwriter": "Best write-only option — full formatting support", "xlsxwriter-constmem": "Memory-optimized write — loses images, comments, row height", diff --git a/tests/test_env_fallback_contracts.py b/tests/test_env_fallback_contracts.py index 7efe564..f378169 100644 --- a/tests/test_env_fallback_contracts.py +++ b/tests/test_env_fallback_contracts.py @@ -331,7 +331,8 @@ def available(self) -> bool: row = results["engines"]["live"] assert row["status"] == "failed" assert "driver crashed" in row["details"]["error"] - assert row["preservation_score"] is None + assert row["preserved"] is None + assert row["feature_preservation"] is None def test_run_mutation_suite_passes_when_mutations_land( @@ -371,11 +372,14 @@ def available(self) -> bool: 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 + assert row["preserved"] is True + assert row["edits_applied"] is True + assert row["features_changed"] == {} + present = len(row["features_present"]) + assert row["feature_preservation"] == f"{present}/{present}" -def test_run_mutation_suite_flags_integrity_when_values_do_not_land( +def test_run_mutation_suite_reports_missing_edits( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: template = _write_template_with_manifest(tmp_path) @@ -402,9 +406,10 @@ def available(self) -> bool: 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"] + assert row["status"] == "edits-missing" + assert row["edits_applied"] is False + assert row["preserved"] is False + assert [edit["applied"] for edit in row["details"]["edits"]] == [False, False] def test_mutations_for_engine_substitutes_placeholder() -> None: @@ -417,11 +422,35 @@ def test_mutations_for_engine_substitutes_placeholder() -> None: 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_run_mutation_suite_fails_unreadable_output( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + template = _write_template_with_manifest(tmp_path) + + def _garbage( + engine: Any, + template: Path, + output: Path, + mutations: list[dict[str, Any]], + ) -> tuple[float, float]: + output.write_bytes(b"not an xlsx") + return 5.0, 1024.0 + + monkeypatch.setattr(mutation_module, "_run_subprocess_mutation", _garbage) + + class _GarbageEngine(_UnavailableEngine): + name = "garbage" + + def available(self) -> bool: + return True + + monkeypatch.setattr( + mutation_module, "modifiable_engines", lambda: [_GarbageEngine()] + ) + results = mutation_module.run_mutation_suite(template, tmp_path / "out", repeats=1) + row = results["engines"]["garbage"] + assert row["status"] == "failed" + assert "not a zip archive" in row["details"]["error"] def test_parse_time_output_extracts_elapsed_and_rss() -> None: @@ -445,9 +474,7 @@ def test_package_integrity_helpers_flag_damage() -> None: rels_ns = "http://schemas.openxmlformats.org/package/2006/relationships" parts = { "xl/_rels/workbook.xml.rels": ( - '' @@ -531,60 +558,50 @@ def test_optional_engines_report_absence(monkeypatch: pytest.MonkeyPatch) -> Non def test_mutation_report_renders_all_verdict_branches(tmp_path: Path) -> None: + def scored( + status: str, + preserved: bool | None, + edits: bool | None, + changed: dict[str, int] | None, + ) -> dict[str, Any]: + return { + "available": status != "unavailable", + "status": status, + "wall_ms_median": None, + "peak_rss_kb_median": None, + "preserved": preserved, + "edits_applied": edits, + "feature_preservation": None, + "features_present": None, + "features_changed": changed, + "details": {}, + } + 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": {}, - }, + "perfect": scored("passed", True, True, {}), + "lossy": scored("passed", False, True, {"charts": 2, "custom_xml": 1}), + # Missing edits outrank collateral changes. + "lazy": scored("edits-missing", False, False, {"cells": 2}), + "crashed": scored("failed", None, None, None), + "ghost": scored("unavailable", None, None, None), }, } 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"]) + verdicts = {name: row["verdict"] for name, row in persisted["engines"].items()} + assert verdicts == { + "perfect": "Preserved", + "lossy": "Changed charts, custom_xml", + "lazy": "Edits missing", + "crashed": "Failed", + "ghost": "Unavailable", + } readme = (tmp_path / "README.md").read_text() - for marker in ("Preserved", "Loss detected", "Mutation integrity failed", "Failed"): - assert marker in readme, marker + for verdict in verdicts.values(): + assert f"| {verdict} |" in readme, verdict # -------------------------------------------------------------------------- diff --git a/tests/test_mutation_suite.py b/tests/test_mutation_suite.py index 5657b48..22b7f90 100644 --- a/tests/test_mutation_suite.py +++ b/tests/test_mutation_suite.py @@ -6,7 +6,9 @@ import shutil import subprocess import sys +from collections.abc import Callable from pathlib import Path +from typing import Any from zipfile import ZIP_DEFLATED, ZipFile import openpyxl @@ -19,10 +21,16 @@ REPO_ROOT = Path(__file__).resolve().parents[1] BUILDER = REPO_ROOT / "scripts" / "build_mutation_template.py" TEMPLATE = REPO_ROOT / "fixtures" / "mutation" / "template_corporate_model.xlsx" +MANIFEST = TEMPLATE.with_name("manifest.json") SOFFICE = Path(shutil.which("soffice") or "/opt/homebrew/bin/soffice") requires_libreoffice = pytest.mark.skipif( not SOFFICE.is_file(), reason="LibreOffice binary not available" ) +MUTATIONS: list[dict[str, Any]] = [ + {"sheet": "Inputs", "cell": "B2", "value": "MUTATED-test"}, + {"sheet": "Inputs", "cell": "C3", "value": 1337}, +] +Parts = dict[str, bytes] def _sha256(path: Path) -> str: @@ -30,65 +38,143 @@ def _sha256(path: Path) -> str: 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 _read_parts(path: Path) -> Parts: + """Read every member of a zip package.""" + with ZipFile(path) as archive: + return {name: archive.read(name) for name in archive.namelist()} -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" +def _write_parts(path: Path, parts: Parts) -> Path: + """Write members into a new zip package.""" with ZipFile(path, "w", compression=ZIP_DEFLATED) as archive: for name, payload in parts.items(): archive.writestr(name, payload) + return path + + +def _replace(parts: Parts, name: str, old: bytes, new: bytes) -> None: + """Replace one exact byte sequence inside a part, failing if it is absent.""" + assert old in parts[name], (name, old) + parts[name] = parts[name].replace(old, new) + + +def _rename(parts: Parts, old: str, new: str) -> None: + """Move a part to a new name.""" + parts[new] = parts.pop(old) + + +def _correct_output() -> Parts: + """Template parts with exactly the two declared edits applied in place.""" + parts = _read_parts(TEMPLATE) + sheet = "xl/worksheets/sheet1.xml" + _replace( + parts, + sheet, + b'20', + b'MUTATED-test', + ) + _replace( + parts, + sheet, + b'60', + b'1337', + ) + return parts + + +def _equivalent_rewrite(parts: Parts) -> Parts: + """Re-serialize a correct output the way a non-copying engine might. + + Renames the comment, drawing, chart and custom XML parts, renumbers + relationship ids, and re-encodes the custom XML with other prefixes, quoting, + whitespace and declaration. + """ + parts = dict(parts) + types = "[Content_Types].xml" + + _rename(parts, "xl/comments/comment1.xml", "xl/comments1.xml") + _replace(parts, types, b"/xl/comments/comment1.xml", b"/xl/comments1.xml") + sheet1_rels = "xl/worksheets/_rels/sheet1.xml.rels" + _replace(parts, sheet1_rels, b"/xl/comments/comment1.xml", b"../comments1.xml") + _replace(parts, sheet1_rels, b'Id="comments"', b'Id="rId9"') + + _rename(parts, "xl/drawings/drawing1.xml", "xl/drawings/drawing7.xml") + _rename( + parts, + "xl/drawings/_rels/drawing1.xml.rels", + "xl/drawings/_rels/drawing7.xml.rels", + ) + _replace(parts, types, b"/xl/drawings/drawing1.xml", b"/xl/drawings/drawing7.xml") + sheet3_rels = "xl/worksheets/_rels/sheet3.xml.rels" + _replace(parts, sheet3_rels, b"/xl/drawings/drawing1.xml", b"../drawings/drawing7.xml") + _replace(parts, sheet3_rels, b'Id="rId1"', b'Id="rId42"') + _replace(parts, "xl/worksheets/sheet3.xml", b'r:id="rId1"', b'r:id="rId42"') + + _rename(parts, "xl/charts/chart1.xml", "xl/charts/chart5.xml") + _replace(parts, types, b"/xl/charts/chart1.xml", b"/xl/charts/chart5.xml") + drawing_rels = "xl/drawings/_rels/drawing7.xml.rels" + _replace(parts, drawing_rels, b"/xl/charts/chart1.xml", b"../charts/chart5.xml") + for name in (drawing_rels, "xl/drawings/drawing7.xml"): + parts[name] = ( + parts[name] + .replace(b'"rId1"', b'"rIdA"') + .replace(b'"rId2"', b'"rId1"') + .replace(b'"rIdA"', b'"rId2"') + ) + + _rename(parts, "customXml/item1.xml", "customXml/item3.xml") + _rename(parts, "customXml/_rels/item1.xml.rels", "customXml/_rels/item3.xml.rels") + _rename(parts, "customXml/itemProps1.xml", "customXml/itemProps3.xml") + _replace(parts, "_rels/.rels", b"customXml/item1.xml", b"/customXml/item3.xml") + _replace(parts, "_rels/.rels", b'Id="rId4"', b'Id="rId11"') + _replace(parts, types, b"/customXml/itemProps1.xml", b"/customXml/itemProps3.xml") + parts["customXml/_rels/item3.xml.rels"] = ( + b"" + ) + parts["customXml/item3.xml"] = ( + b"" + b"openpyxl-targeted-fixture" + ) + parts["customXml/itemProps3.xml"] = ( + b"\n" + b"" + b"" + ) + return parts + + +def _drop_chart(parts: Parts) -> None: + del parts["xl/charts/chart1.xml"] + + +def _drop_comment(parts: Parts) -> None: + del parts["xl/comments/comment1.xml"] + + +def _drop_custom_xml(parts: Parts) -> None: + del parts["customXml/item1.xml"] 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 + """Repeated generation writes the same package bytes. + + The builder writes to the committed fixture path, and openpyxl's output depends on + whether lxml is installed, so the committed fixture and manifest are restored + afterwards: every other test must score against the committed input. + """ + committed = {path: path.read_bytes() for path in (TEMPLATE, MANIFEST)} + try: + 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 + finally: + for path, payload in committed.items(): + path.write_bytes(payload) @requires_libreoffice @@ -119,58 +205,112 @@ def test_template_opens_in_openpyxl_and_libreoffice(tmp_path: Path) -> None: 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) +def test_equivalent_rewrite_scores_the_same_as_in_place_edit(tmp_path: Path) -> None: + """Renamed parts, renumbered rIds and re-encoded customXml are not content changes.""" + in_place = _write_parts(tmp_path / "in_place.xlsx", _correct_output()) + rewritten = _write_parts(tmp_path / "rewritten.xlsx", _equivalent_rewrite(_correct_output())) + + in_place_score = score_preservation(TEMPLATE, in_place, MUTATIONS) + rewritten_score = score_preservation(TEMPLATE, rewritten, MUTATIONS) + + for score in (in_place_score, rewritten_score): + assert score["preserved"] is True + assert score["edits_applied"] is True + assert score["features_changed"] == {} + assert score["integrity"] == {"dangling_rels": [], "missing_content_types": []} + present = rewritten_score["features_present"] + assert {"charts", "comments", "custom_xml"} <= set(present) + assert rewritten_score["feature_preservation"] == f"{len(present)}/{len(present)}" + assert rewritten_score["diagnostics"]["lost_parts"] # renamed parts are only diagnostics + + +@pytest.mark.parametrize( + ("drop", "feature"), + [ + (_drop_chart, "charts"), + (_drop_comment, "comments"), + (_drop_custom_xml, "custom_xml"), + ], +) +def test_dropped_content_is_reported_under_its_feature( + tmp_path: Path, drop: Callable[[Parts], None], feature: str +) -> None: + """Losing a chart, a comment or customXml is a change to exactly that feature.""" + parts = _correct_output() + drop(parts) + output = _write_parts(tmp_path / "output.xlsx", parts) + + score = score_preservation(TEMPLATE, output, MUTATIONS) + + assert score["preserved"] is False + assert score["edits_applied"] is True + assert set(score["features_changed"]) == {feature} + present = len(score["features_present"]) + assert score["feature_preservation"] == f"{present - 1}/{present}" + assert score["sample"][0]["feature"] == feature + + +def test_unapplied_edits_are_reported_separately(tmp_path: Path) -> None: + """A byte copy of the template keeps every feature but misses the edits.""" + output = tmp_path / "copy.xlsx" + shutil.copyfile(TEMPLATE, output) + + score = score_preservation(TEMPLATE, output, MUTATIONS) + + assert score["edits_applied"] is False + assert score["preserved"] is False + assert [edit["applied"] for edit in score["edits"]] == [False, False] + assert score["edits"][1]["actual"] == {"type": "n", "value": 60.0} + assert set(score["features_changed"]) == {"cells"} + + +def test_recomputed_formula_results_are_not_changes(tmp_path: Path) -> None: + """Writing a cached result into a formula cell is recalculation, not a content change.""" + parts = _correct_output() + _replace( + parts, + "xl/worksheets/sheet2.xml", + b'SUM(B2:B9)', + b'SUM(B2:B9)8960', + ) + output = _write_parts(tmp_path / "output.xlsx", parts) - assert "customXml/item1.xml" in result["details"]["lost_parts"] - assert result["details"]["customXml_identical"] is False - assert result["preservation_score"] < 100 + assert score_preservation(TEMPLATE, output, MUTATIONS)["preserved"] is True -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") +def test_integrity_issues_are_reported_but_not_scored(tmp_path: Path) -> None: + """A dangling relationship is an integrity finding, separate from preservation.""" + parts = _correct_output() + _replace( + parts, + "xl/worksheets/_rels/sheet1.xml.rels", + b"", + b'', + ) + output = _write_parts(tmp_path / "output.xlsx", parts) - result = score_preservation(template, output) + score = score_preservation(TEMPLATE, output, MUTATIONS) - assert result["details"]["dangling_rels"] == [ - "xl/_rels/workbook.xml.rels: xl/worksheets/missing.xml" + assert score["integrity"]["dangling_rels"] == [ + "xl/worksheets/_rels/sheet1.xml.rels: xl/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 + assert score["preserved"] is True 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 set(engines) == { + "openpyxl", + "wolfxl", + "aspose-cells-foss", + "zavora-xlsx", + "sheetjs", + "exceljs", + "libreoffice", + } assert all(isinstance(available, bool) for available in engines.values()) @@ -187,15 +327,21 @@ def test_renderer_writes_comparison_files(tmp_path: Path) -> None: "status": "passed", "wall_ms_median": 12.5, "peak_rss_kb_median": 2048.0, - "preservation_score": 90.0, - "details": {"lost_parts": ["customXml/item1.xml"]}, + "preserved": False, + "edits_applied": True, + "feature_preservation": "16/17", + "features_present": [], + "features_changed": {"custom_xml": 1}, + "details": {"integrity": {"dangling_rels": [], "missing_content_types": []}}, } }, } 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") + assert '"verdict": "Changed custom_xml"' in (tmp_path / "results.json").read_text( + encoding="utf-8" + ) + assert ( + "| openpyxl | 12.500 | 2048.000 | 16/17 | custom_xml (1) | yes | ok | Changed custom_xml |" + ) in (tmp_path / "README.md").read_text(encoding="utf-8") diff --git a/tools/external-oracles/apache-poi/Dockerfile b/tools/external-oracles/apache-poi/Dockerfile new file mode 100644 index 0000000..dd4333d --- /dev/null +++ b/tools/external-oracles/apache-poi/Dockerfile @@ -0,0 +1,26 @@ +# syntax=docker/dockerfile:1 +# Apache POI 5.5.1 oracle helper image for remote Docker runs. +# Build (see ../remote/README.md): +# docker --context pc build --build-context oracle-remote=../remote \ +# -t excelbench-poi-oracle:5.5.1 . +FROM eclipse-temurin:21-jdk@sha256:3e3c176ffed168beb42c607be9bc1639b466cf00261a0fb04425562c9d0c5c2b + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends python3 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/excelbench/apache-poi +COPY build.sh fetch_deps.py poi_oracle.py ./ +COPY src/ src/ +# fetch_deps.py verifies Maven Central checksums; build.sh compiles and runs the self-test. +RUN ./build.sh + +COPY --from=oracle-remote container_entry.py /opt/excelbench/remote/container_entry.py + +LABEL org.excelbench.adapter=apache-poi \ + org.excelbench.library=org.apache.poi:poi-ooxml \ + org.excelbench.library-version=5.5.1 + +ENTRYPOINT ["python3", "/opt/excelbench/remote/container_entry.py", \ + "--cwd", "/opt/excelbench/apache-poi", "--", \ + "python3", "/opt/excelbench/apache-poi/poi_oracle.py"] diff --git a/tools/external-oracles/apache-poi/Dockerfile.dockerignore b/tools/external-oracles/apache-poi/Dockerfile.dockerignore new file mode 100644 index 0000000..901e895 --- /dev/null +++ b/tools/external-oracles/apache-poi/Dockerfile.dockerignore @@ -0,0 +1,3 @@ +build/ +deps/ +__pycache__/ diff --git a/tools/external-oracles/excelize/Dockerfile b/tools/external-oracles/excelize/Dockerfile new file mode 100644 index 0000000..44e2037 --- /dev/null +++ b/tools/external-oracles/excelize/Dockerfile @@ -0,0 +1,30 @@ +# syntax=docker/dockerfile:1 +# Excelize v2.10.1 oracle helper image for remote Docker runs. +# Build (see ../remote/README.md): +# docker --context pc build --build-context oracle-remote=../remote \ +# -t excelbench-excelize-oracle:2.10.1 . +FROM golang:1.25-trixie@sha256:2c4c60ef415fbfa5e90300722293bef36c5e63fae17570ce18f580af933dbd73 AS build + +ENV GOTOOLCHAIN=local CGO_ENABLED=0 +WORKDIR /src +COPY go.mod go.sum ./ +RUN go mod download && go mod verify +COPY *.go ./ +RUN go test ./... && go build -trimpath -o /out/excelize-oracle . + +FROM debian:trixie-slim@sha256:a99cfc517144bc59b1978475ec53b46ecabec7e43635402ee5b77cc54cd1b20a + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends python3 \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=build /out/excelize-oracle /opt/excelbench/excelize/excelize-oracle +COPY --from=oracle-remote container_entry.py /opt/excelbench/remote/container_entry.py + +LABEL org.excelbench.adapter=excelize \ + org.excelbench.library=github.com/xuri/excelize/v2 \ + org.excelbench.library-version=v2.10.1 + +ENTRYPOINT ["python3", "/opt/excelbench/remote/container_entry.py", \ + "--cwd", "/opt/excelbench/excelize", "--", \ + "/opt/excelbench/excelize/excelize-oracle"] diff --git a/tools/external-oracles/exceljs/README.md b/tools/external-oracles/exceljs/README.md index 9d84c0c..93005e8 100644 --- a/tools/external-oracles/exceljs/README.md +++ b/tools/external-oracles/exceljs/README.md @@ -1,17 +1,66 @@ -# ExcelJS External Oracle +# ExcelJS Helper -This optional helper generates `.xlsx` workbooks with ExcelJS. It uses the same -JSON stdin/stdout contract as the Excelize, LibreOffice, ClosedXML, and NPOI -helpers. +This directory backs two things: -Run from this directory once dependencies are installed: +- the scored ExcelBench `exceljs` adapter + (`src/excelbench/harness/adapters/exceljs_adapter.py`), which drives ExcelJS + read, write, and template-mutation runs through this helper; and +- the original ExcelJS external oracle (`write_fixture`, `read_metadata`). + +Both use the same JSON stdin/stdout contract as the Excelize, LibreOffice, +ClosedXML, and NPOI helpers: one JSON request on stdin, one JSON object on +stdout, exit code 0 on success. Failures print +`{"error": "exceljs_oracle_failed", "message": ...}` and exit 1. + +Install the pinned dependencies (ExcelJS 4.4.0, JSZip 3.10.1) once: ```bash npm install -npm run oracle +npm run oracle # node exceljs-oracle.cjs ``` -Supported operations: +## Adapter operations (`exceljs-model.cjs`) + +- `describe`: library slug `exceljs`, the installed ExcelJS version, and the + write operations ExcelJS cannot express. +- `read_model` (`input_path`): loads the workbook with `workbook.xlsx.readFile` + and reports what the ExcelJS object model exposes: cell values and formulas, + fonts, fills, number formats, alignment, borders, row heights, column widths, + merges, conditional formats, data validations, hyperlinks, images, notes, + sheet views, defined names, tables, sheet protection, page setup, and + header/footer text. +- `write_model` (`output_path`, `payload.ops`): replays ExcelBench write calls + through the ExcelJS API (`addWorksheet`, `cell.value`, cell styles, + `addConditionalFormatting`, `dataValidations.add`, `addImage`, `cell.note`, + `worksheet.views`, `definedNames.add`, `addTable`, `protect`, `pageSetup`, + `headerFooter`) and saves with `workbook.xlsx.writeFile`. +- `mutate` (`input_path`, `output_path`, `payload.mutations`): loads an existing + workbook, sets each cell value, and writes a new package. + +Declared unsupported (ExcelJS 4.4.0 has no API for them): + +- pivot tables: not loaded on read, no creation API; +- charts: not loaded on read, no creation API. + +Known ExcelJS 4.4.0 behavior that surfaces as failed test cases rather than +being worked around: + +- Loading some workbooks with drawings or tables throws (for example + `Cannot read properties of undefined (reading 'anchors')`); `read_model` and + `mutate` report that error. +- Defined names lose their sheet scope (`localSheetId`), and `definedNames.add` + cannot write a sheet-scoped name. +- Hyperlink tooltips and location-only (internal) hyperlinks are dropped on + read; internal hyperlinks are written with both a relationship and a location. +- Conditional formatting rules have no `stopIfTrue` support. +- Notes have no author. +- Page setup always carries ExcelJS defaults (`orientation`, `scale`, + `fitToWidth`, `fitToHeight`) on read and write. +- The legacy `password` attribute of sheet protection is not read. +- Images are written as `oneCellAnchor` elements carrying an `editAs` + attribute. + +## Oracle operations (`exceljs-oracle.cjs`) - `write_fixture`: writes sheets, cells, formulas, styles, rich text, comments, hyperlinks, tables, data validations, merged ranges, freeze panes, images, @@ -19,6 +68,3 @@ Supported operations: - `read_metadata`: inspects package parts for worksheets, tables, drawings, media, comments, VML drawings, shared strings, calc-chain metadata, and data validations. - -ExcelJS is intentionally a local pre-release oracle, not a normal ExcelBench -adapter or public benchmark claim. diff --git a/tools/external-oracles/exceljs/exceljs-model.cjs b/tools/external-oracles/exceljs/exceljs-model.cjs new file mode 100644 index 0000000..fe9168b --- /dev/null +++ b/tools/external-oracles/exceljs/exceljs-model.cjs @@ -0,0 +1,919 @@ +// ExcelBench JSON-model operations for ExcelJS: describe, read_model, +// write_model, mutate. Every value reported here comes from the ExcelJS object +// model after `workbook.xlsx.readFile`; every write goes through the public +// ExcelJS API. Behavior ExcelJS loses or cannot express is left to fail the +// corresponding ExcelBench test case. +const fs = require("node:fs/promises"); +const path = require("node:path"); + +const ExcelJS = require("exceljs"); +const EXCELJS_VERSION = require("exceljs/package.json").version; + +const { ValueType } = ExcelJS; + +const UNSUPPORTED_READ = { + pivot_tables: "ExcelJS 4.4.0 does not load pivot table parts; no pivot table read API", + chart_anchors: "ExcelJS 4.4.0 does not load chart parts; no chart read API", +}; + +const UNSUPPORTED_WRITE = { + pivot: "ExcelJS 4.4.0 has no pivot table creation API", + chart: "ExcelJS 4.4.0 has no chart creation API", +}; + +// Error literal -> formula that produces it (contract write table). +const 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", +}; + +function describe() { + return { + library: "exceljs", + version: EXCELJS_VERSION, + capabilities: ["read", "write", "modify"], + unsupported_write: { ...UNSUPPORTED_WRITE }, + }; +} + +// =========================================================================== +// read_model +// =========================================================================== + +async function readModel(request) { + const inputPath = requirePath(request, "input_path", "read_model"); + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.readFile(inputPath); + return { + model: { + unsupported: { ...UNSUPPORTED_READ }, + named_ranges: readNamedRanges(workbook), + sheets: workbook.worksheets.map((worksheet) => readSheet(workbook, worksheet)), + }, + }; +} + +function readNamedRanges(workbook) { + // ExcelJS keeps only {name, ranges}; localSheetId is discarded on load, so + // every name it exposes is workbook-scoped. + return workbook.definedNames.model.map((definedName) => ({ + name: definedName.name, + scope: "workbook", + sheet: null, + refers_to: definedName.ranges.join(","), + })); +} + +function readSheet(workbook, worksheet) { + const sheetModel = worksheet.model; + const cells = {}; + const rowHeights = {}; + const hyperlinks = []; + const comments = []; + + worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { + if (typeof row.height === "number") { + rowHeights[String(rowNumber)] = row.height; + } + row.eachCell({ includeEmpty: true }, (cell) => { + const entry = {}; + const value = readCellValue(cell); + if (value) entry.value = value; + const format = readCellFormat(cell); + if (Object.keys(format).length) entry.format = format; + const border = readCellBorder(cell); + if (Object.keys(border).length) entry.border = border; + if (Object.keys(entry).length) cells[cell.address] = entry; + + if (cell.type === ValueType.Hyperlink && cell.hyperlink) { + hyperlinks.push({ + cell: cell.address, + target: cell.hyperlink, + display: cell.text, + tooltip: cell.value.tooltip ?? null, + // ExcelJS only reconciles relationship-backed (external) hyperlinks; + // location-only links are dropped on load. + internal: false, + }); + } + if (cell.note) { + comments.push({ + cell: cell.address, + text: noteText(cell.note), + author: null, + threaded: false, + }); + } + }); + }); + + const columnWidths = {}; + for (const column of worksheet.columns || []) { + if (typeof column.width === "number") { + columnWidths[column.letter] = column.width; + } + } + + return { + name: worksheet.name, + cells, + row_heights: rowHeights, + column_widths: columnWidths, + merged_ranges: [...(sheetModel.merges || [])], + conditional_formats: readConditionalFormats(worksheet), + data_validations: readDataValidations(worksheet), + hyperlinks, + images: readImages(workbook, worksheet), + pivot_tables: [], + comments, + freeze_panes: readFreezePanes(worksheet), + tables: readTables(worksheet), + sheet_protection: readSheetProtection(worksheet), + page_setup: readPageSetup(worksheet), + chart_anchors: [], + }; +} + +function readCellValue(cell) { + const raw = cell.value; + switch (cell.type) { + case ValueType.Null: + case ValueType.Merge: + // Merge cells are ExcelJS placeholders that proxy the master cell value. + return null; + case ValueType.Number: + return { type: "number", value: raw, formula: null }; + case ValueType.String: + case ValueType.SharedString: + case ValueType.RichText: + case ValueType.Hyperlink: + return { type: "string", value: cell.text, formula: null }; + case ValueType.Boolean: + return { type: "boolean", value: raw, formula: null }; + case ValueType.Date: + return dateValue(raw); + case ValueType.Error: + return { type: "error", value: raw.error, formula: null }; + case ValueType.Formula: { + const result = cell.result; + if (result && typeof result === "object" && typeof result.error === "string") { + return { type: "error", value: result.error, formula: null }; + } + const text = `=${cell.formula}`; + return { type: "formula", value: text, formula: text }; + } + default: + return null; + } +} + +function dateValue(date) { + const iso = date.toISOString(); + const midnight = + date.getUTCHours() === 0 && + date.getUTCMinutes() === 0 && + date.getUTCSeconds() === 0 && + date.getUTCMilliseconds() === 0; + return midnight + ? { type: "date", value: iso.slice(0, 10), formula: null } + : { type: "datetime", value: iso.slice(0, 19), formula: null }; +} + +function readCellFormat(cell) { + const format = {}; + const font = cell.font || {}; + if (font.bold) format.bold = true; + if (font.italic) format.italic = true; + if (font.underline) { + format.underline = font.underline === true ? "single" : String(font.underline); + } + if (font.strike) format.strikethrough = true; + if (font.name) format.font_name = font.name; + if (typeof font.size === "number") format.font_size = font.size; + const fontColor = argbToHex(font.color); + if (fontColor) format.font_color = fontColor; + + const fill = cell.fill; + if (fill && fill.type === "pattern" && fill.pattern === "solid") { + const bg = argbToHex(fill.fgColor); + if (bg) format.bg_color = bg; + } + if (cell.numFmt) format.number_format = cell.numFmt; + + const alignment = cell.alignment || {}; + if (alignment.horizontal) format.h_align = alignment.horizontal; + if (alignment.vertical) { + // ExcelJS names OOXML vertical="center" as "middle". + format.v_align = alignment.vertical === "middle" ? "center" : alignment.vertical; + } + if (alignment.wrapText) format.wrap = true; + if (alignment.textRotation) { + // ExcelJS names OOXML textRotation="255" as "vertical". + format.rotation = alignment.textRotation === "vertical" ? 255 : alignment.textRotation; + } + if (alignment.indent) format.indent = alignment.indent; + return format; +} + +function readCellBorder(cell) { + const border = cell.border || {}; + const out = {}; + for (const edge of ["top", "bottom", "left", "right"]) { + const item = borderEdge(border[edge]); + if (item) out[edge] = item; + } + const diagonal = border.diagonal; + if (diagonal) { + const item = borderEdge(diagonal); + if (item && diagonal.up) out.diagonal_up = item; + if (item && diagonal.down) out.diagonal_down = item; + } + return out; +} + +function borderEdge(side) { + if (!side || !side.style) return null; + const item = { style: side.style }; + const color = argbToHex(side.color); + if (color) item.color = color; + return item; +} + +function readConditionalFormats(worksheet) { + const out = []; + for (const cf of worksheet.conditionalFormattings || []) { + for (const rule of cf.rules || []) { + const style = rule.style || {}; + const format = {}; + const fill = style.fill; + if (fill) { + // Differential fills carry the solid colour in bgColor (fgColor mirrors it). + const bg = argbToHex(fill.bgColor) || argbToHex(fill.fgColor); + if (bg) format.bg_color = bg; + } + const fontColor = style.font ? argbToHex(style.font.color) : null; + if (fontColor) format.font_color = fontColor; + const formulae = rule.formulae || []; + out.push({ + range: cf.ref, + rule_type: rule.type ?? null, + operator: rule.operator ?? null, + formula: formulae.length ? String(formulae[0]) : null, + priority: typeof rule.priority === "number" ? rule.priority : null, + stop_if_true: typeof rule.stopIfTrue === "boolean" ? rule.stopIfTrue : null, + format, + }); + } + } + return out; +} + +function readDataValidations(worksheet) { + const out = []; + for (const [address, dv] of Object.entries(worksheet.dataValidations.model || {})) { + if (!dv) continue; + const formulae = dv.formulae || []; + const formula1 = formulae.length > 0 ? formulaText(formulae[0]) : null; + const formula2 = formulae.length > 1 ? formulaText(formulae[1]) : null; + let operator = dv.operator ?? null; + if (operator === null && formula2 !== null) operator = "between"; + out.push({ + range: address.replace(/^range:/, ""), + validation_type: dv.type ?? null, + operator, + formula1, + formula2, + allow_blank: typeof dv.allowBlank === "boolean" ? dv.allowBlank : null, + show_input: typeof dv.showInputMessage === "boolean" ? dv.showInputMessage : null, + show_error: typeof dv.showErrorMessage === "boolean" ? dv.showErrorMessage : null, + prompt_title: dv.promptTitle ?? null, + prompt: dv.prompt ?? null, + error_title: dv.errorTitle ?? null, + error: dv.error ?? null, + }); + } + return out; +} + +function formulaText(value) { + if (value === null || value === undefined) return null; + if (value instanceof Date) return value.toISOString(); + return String(value); +} + +function readImages(workbook, worksheet) { + return worksheet.getImages().map((image) => { + const range = image.range || {}; + const tl = range.tl; + const medium = workbook.getImage(image.imageId); + return { + cell: tl ? `${columnLetter(tl.nativeCol + 1)}${tl.nativeRow + 1}` : null, + path: medium && medium.name ? `/xl/media/${medium.name}.${medium.extension}` : null, + anchor: tl ? (range.br ? "twoCell" : "oneCell") : null, + offset: tl ? [tl.nativeColOff, tl.nativeRowOff] : null, + alt_text: null, + }; + }); +} + +function readFreezePanes(worksheet) { + const view = (worksheet.views || [])[0]; + if (!view) return {}; + if (view.state === "frozen") { + const out = { mode: "freeze" }; + if (view.topLeftCell) out.top_left_cell = view.topLeftCell; + return out; + } + if (view.state === "split") { + const out = { + mode: "split", + x_split: typeof view.xSplit === "number" ? view.xSplit : null, + y_split: typeof view.ySplit === "number" ? view.ySplit : null, + }; + if (view.topLeftCell) out.top_left_cell = view.topLeftCell; + if (view.activePane) out.active_pane = view.activePane; + return out; + } + return {}; +} + +function readTables(worksheet) { + return worksheet.getTables().map((table) => { + const model = table.model || {}; + const style = model.style || {}; + return { + name: model.name ?? null, + ref: model.tableRef ?? model.ref ?? null, + header_row: Boolean(model.headerRow), + totals_row: Boolean(model.totalsRow), + style: style.theme ?? null, + columns: (model.columns || []).map((column) => column.name), + autofilter: Boolean(model.autoFilterRef), + }; + }); +} + +function readSheetProtection(worksheet) { + const sp = worksheet.sheetProtection; + if (!sp) { + return { + protected: false, + password_hash_present: false, + format_cells: null, + insert_rows: null, + select_locked_cells: null, + select_unlocked_cells: null, + sort: null, + auto_filter: null, + }; + } + // ExcelJS models protection options as "allowed" flags whose defaults + // (absent attribute) match OOXML: formatCells/insertRows/sort/autoFilter are + // disallowed unless true, select*Cells are allowed unless false. The + // contract uses raw OOXML semantics (true == blocked). + return { + protected: sp.sheet === true, + password_hash_present: Boolean(sp.hashValue), + format_cells: sp.formatCells !== true, + insert_rows: sp.insertRows !== true, + select_locked_cells: sp.selectLockedCells === false, + select_unlocked_cells: sp.selectUnlockedCells === false, + sort: sp.sort !== true, + auto_filter: sp.autoFilter !== true, + }; +} + +function readPageSetup(worksheet) { + const ps = worksheet.pageSetup || {}; + const hf = worksheet.headerFooter || {}; + return { + orientation: ps.orientation ?? null, + fit_to_width: typeof ps.fitToWidth === "number" ? ps.fitToWidth : null, + fit_to_height: typeof ps.fitToHeight === "number" ? ps.fitToHeight : null, + scale: typeof ps.scale === "number" ? ps.scale : null, + // ExcelJS stores print title rows as "1:2" (no "$"). + print_title_rows: ps.printTitlesRow ? absoluteRowRange(ps.printTitlesRow) : null, + header_center: centerSection(hf.oddHeader), + footer_center: centerSection(hf.oddFooter), + }; +} + +function absoluteRowRange(value) { + return String(value) + .split(":") + .map((part) => `$${part}`) + .join(":"); +} + +// Split an OOXML header/footer string into its &L/&C/&R sections. +function centerSection(text) { + if (!text) return null; + const sections = {}; + let current = "C"; + let buffer = ""; + for (let i = 0; i < text.length; i += 1) { + const ch = text[i]; + if (ch === "&" && i + 1 < text.length) { + const next = text[i + 1]; + if (next === "L" || next === "C" || next === "R") { + sections[current] = (sections[current] || "") + buffer; + buffer = ""; + current = next; + i += 1; + continue; + } + buffer += ch + next; + i += 1; + continue; + } + buffer += ch; + } + sections[current] = (sections[current] || "") + buffer; + return sections.C ? sections.C : null; +} + +// =========================================================================== +// write_model +// =========================================================================== + +async function writeModel(request) { + const outputPath = requirePath(request, "output_path", "write_model"); + const ops = (request.payload && request.payload.ops) || []; + const workbook = new ExcelJS.Workbook(); + + for (const op of ops) { + if (op.op === "add_sheet") workbook.addWorksheet(op.name); + } + for (const op of ops) { + await applyOp(workbook, op); + } + + await fs.mkdir(path.dirname(path.resolve(outputPath)), { recursive: true }); + await workbook.xlsx.writeFile(outputPath); + return { written: outputPath }; +} + +async function applyOp(workbook, op) { + switch (op.op) { + case "add_sheet": + return; + case "cell_value": + writeCellValue(sheetOf(workbook, op.sheet).getCell(op.cell), op); + return; + case "cell_format": + writeCellFormat(sheetOf(workbook, op.sheet).getCell(op.cell), op.format || {}); + return; + case "cell_border": + writeCellBorder(sheetOf(workbook, op.sheet).getCell(op.cell), op.border || {}); + return; + case "row_height": + sheetOf(workbook, op.sheet).getRow(Number(op.row)).height = Number(op.height); + return; + case "column_width": + sheetOf(workbook, op.sheet).getColumn(op.column).width = Number(op.width); + return; + case "merge": + sheetOf(workbook, op.sheet).mergeCells(op.range); + return; + case "conditional_format": + writeConditionalFormat(sheetOf(workbook, op.sheet), op.rule || {}); + return; + case "data_validation": + writeDataValidation(sheetOf(workbook, op.sheet), op.validation || {}); + return; + case "hyperlink": + writeHyperlink(sheetOf(workbook, op.sheet), op.link || {}); + return; + case "image": + await writeImage(workbook, sheetOf(workbook, op.sheet), op.image || {}); + return; + case "comment": { + const comment = op.comment || {}; + // ExcelJS notes have no author field; only the text is expressible. + sheetOf(workbook, op.sheet).getCell(comment.cell).note = String(comment.text ?? ""); + return; + } + case "freeze": + writeFreeze(sheetOf(workbook, op.sheet), op.settings || {}); + return; + case "named_range": + writeNamedRange(workbook, op.named_range || {}); + return; + case "table": + writeTable(sheetOf(workbook, op.sheet), op.table || {}); + return; + case "protection": + await writeProtection(sheetOf(workbook, op.sheet), op.settings || {}); + return; + case "page_setup": + writePageSetup(sheetOf(workbook, op.sheet), op.settings || {}); + return; + case "pivot": + case "chart": + throw new Error(`${op.op}: ${UNSUPPORTED_WRITE[op.op]}`); + default: + throw new Error(`Unknown write op '${op.op}'.`); + } +} + +function writeCellValue(cell, op) { + const { type, value } = op; + switch (type) { + case "blank": + cell.value = null; + return; + case "string": + cell.value = value === null || value === undefined ? "" : String(value); + return; + case "number": + cell.value = Number(value); + return; + case "boolean": + cell.value = Boolean(value); + return; + case "date": + cell.value = new Date(`${String(value).slice(0, 10)}T00:00:00Z`); + return; + case "datetime": + cell.value = new Date(`${String(value).slice(0, 19)}Z`); + return; + case "formula": { + const text = String(op.formula ?? value ?? ""); + cell.value = { formula: text.replace(/^=/, "") }; + return; + } + case "error": { + const formula = ERROR_FORMULAS[String(value).toUpperCase()]; + if (!formula) throw new Error(`No formula produces error literal '${value}'.`); + cell.value = { formula }; + return; + } + default: + throw new Error(`Unsupported cell value type '${type}'.`); + } +} + +function writeCellFormat(cell, format) { + const font = {}; + if (format.bold !== undefined) font.bold = Boolean(format.bold); + if (format.italic !== undefined) font.italic = Boolean(format.italic); + if (format.underline !== undefined) font.underline = format.underline; + if (format.strikethrough !== undefined) font.strike = Boolean(format.strikethrough); + if (format.font_name !== undefined) font.name = format.font_name; + if (format.font_size !== undefined) font.size = Number(format.font_size); + if (format.font_color !== undefined) font.color = { argb: hexToArgb(format.font_color) }; + if (Object.keys(font).length) cell.font = { ...(cell.font || {}), ...font }; + + if (format.bg_color !== undefined) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: hexToArgb(format.bg_color) }, + }; + } + if (format.number_format !== undefined) cell.numFmt = format.number_format; + + const alignment = {}; + if (format.h_align !== undefined) alignment.horizontal = format.h_align; + if (format.v_align !== undefined) { + alignment.vertical = format.v_align === "center" ? "middle" : format.v_align; + } + if (format.wrap !== undefined) alignment.wrapText = Boolean(format.wrap); + if (format.rotation !== undefined) { + alignment.textRotation = Number(format.rotation) === 255 ? "vertical" : Number(format.rotation); + } + if (format.indent !== undefined) alignment.indent = Number(format.indent); + if (Object.keys(alignment).length) { + cell.alignment = { ...(cell.alignment || {}), ...alignment }; + } +} + +function writeCellBorder(cell, border) { + const out = {}; + for (const edge of ["top", "bottom", "left", "right"]) { + if (border[edge]) out[edge] = borderSpec(border[edge]); + } + const up = border.diagonal_up; + const down = border.diagonal_down; + if (up || down) { + out.diagonal = { ...borderSpec(up || down), up: Boolean(up), down: Boolean(down) }; + } + cell.border = out; +} + +function borderSpec(edge) { + const spec = { style: edge.style }; + if (edge.color) spec.color = { argb: hexToArgb(edge.color) }; + return spec; +} + +function writeConditionalFormat(worksheet, rule) { + const cfRule = { type: rule.rule_type }; + if (typeof rule.priority === "number") cfRule.priority = rule.priority; + switch (rule.rule_type) { + case "cellIs": + cfRule.operator = rule.operator; + cfRule.formulae = rule.formula ? [stripEquals(rule.formula)] : []; + break; + case "expression": + cfRule.formulae = rule.formula ? [stripEquals(rule.formula)] : []; + break; + case "dataBar": + cfRule.cfvo = [{ type: "min" }, { type: "max" }]; + cfRule.color = { argb: "FF638EC6" }; + break; + case "colorScale": + cfRule.cfvo = [{ type: "min" }, { type: "percentile", value: 50 }, { type: "max" }]; + cfRule.color = [{ argb: "FFAA0000" }, { argb: "FFFFFF00" }, { argb: "FF00AA00" }]; + break; + default: + if (rule.operator) cfRule.operator = rule.operator; + if (rule.formula) cfRule.formulae = [stripEquals(rule.formula)]; + } + // ExcelJS has no stopIfTrue rule attribute; the flag cannot be expressed. + const format = rule.format || {}; + const style = {}; + if (format.bg_color) { + const argb = hexToArgb(format.bg_color); + style.fill = { type: "pattern", pattern: "solid", fgColor: { argb }, bgColor: { argb } }; + } + if (format.font_color) style.font = { color: { argb: hexToArgb(format.font_color) } }; + if (Object.keys(style).length) cfRule.style = style; + worksheet.addConditionalFormatting({ ref: rule.range, rules: [cfRule] }); +} + +function writeDataValidation(worksheet, validation) { + const dv = { type: validation.validation_type }; + if (validation.operator) dv.operator = validation.operator; + const formulae = []; + if (validation.formula1 !== null && validation.formula1 !== undefined) { + formulae.push(stripEquals(validation.formula1)); + } + if (validation.formula2 !== null && validation.formula2 !== undefined) { + formulae.push(stripEquals(validation.formula2)); + } + dv.formulae = formulae; + if (validation.allow_blank !== null && validation.allow_blank !== undefined) { + dv.allowBlank = Boolean(validation.allow_blank); + } + if (validation.show_input !== null && validation.show_input !== undefined) { + dv.showInputMessage = Boolean(validation.show_input); + } + if (validation.show_error !== null && validation.show_error !== undefined) { + dv.showErrorMessage = Boolean(validation.show_error); + } + if (validation.prompt_title) dv.promptTitle = validation.prompt_title; + if (validation.prompt) dv.prompt = validation.prompt; + if (validation.error_title) dv.errorTitle = validation.error_title; + if (validation.error) dv.error = validation.error; + worksheet.dataValidations.add(validation.range, dv); +} + +function writeHyperlink(worksheet, link) { + const target = link.internal + ? String(link.target).replace(/^#/, "") + : String(link.target); + const value = { text: String(link.display ?? target), hyperlink: target }; + if (link.tooltip) value.tooltip = link.tooltip; + worksheet.getCell(link.cell).value = value; +} + +async function writeImage(workbook, worksheet, image) { + const filename = image.path; + if (!filename) throw new Error("image op requires an absolute path."); + const buffer = await fs.readFile(filename); + let extension = path.extname(filename).slice(1).toLowerCase(); + if (extension === "jpg") extension = "jpeg"; + const imageId = workbook.addImage({ buffer, extension }); + const { col, row } = decodeCell(image.cell); + if (image.anchor === "twoCell") { + worksheet.addImage(imageId, `${image.cell}:${image.cell}`); + return; + } + // ExcelJS writes a oneCellAnchor when the range has tl + ext (pixels) and no br. + const { width, height } = imagePixelSize(buffer, extension); + worksheet.addImage(imageId, { tl: { col: col - 1, row: row - 1 }, ext: { width, height } }); +} + +function writeFreeze(worksheet, settings) { + if (settings.mode === "freeze") { + const { col, row } = decodeCell(settings.top_left_cell); + worksheet.views = [ + { state: "frozen", xSplit: col - 1, ySplit: row - 1, topLeftCell: settings.top_left_cell }, + ]; + return; + } + if (settings.mode === "split") { + const view = { + state: "split", + xSplit: Number(settings.x_split || 0), + ySplit: Number(settings.y_split || 0), + }; + if (settings.top_left_cell) view.topLeftCell = settings.top_left_cell; + if (settings.active_pane) view.activePane = settings.active_pane; + worksheet.views = [view]; + return; + } + throw new Error(`Unknown freeze mode '${settings.mode}'.`); +} + +function writeNamedRange(workbook, namedRange) { + // ExcelJS DefinedNames.add(location, name) has no scope parameter; every + // name it writes is workbook-scoped. + workbook.definedNames.add(stripEquals(String(namedRange.refers_to)), namedRange.name); +} + +function writeTable(worksheet, table) { + const range = decodeRange(table.ref); + const headerRow = table.header_row !== false; + const totalsRow = Boolean(table.totals_row); + const firstDataRow = range.top + (headerRow ? 1 : 0); + const lastDataRow = range.bottom - (totalsRow ? 1 : 0); + // ExcelJS sizes a table from its rows and rewrites them into the sheet, so + // pass the existing cell values inside the ref as the table rows. + const rows = []; + for (let r = firstDataRow; r <= lastDataRow; r += 1) { + const values = []; + for (let c = range.left; c <= range.right; c += 1) { + values.push(worksheet.getCell(r, c).value); + } + rows.push(values); + } + const columns = (table.columns || []).map((name) => ({ + name: String(name), + filterButton: table.autofilter !== false, + })); + worksheet.addTable({ + name: table.name, + ref: `${columnLetter(range.left)}${range.top}`, + headerRow, + totalsRow, + style: { theme: table.style ?? null }, + columns, + rows, + }); +} + +async function writeProtection(worksheet, settings) { + if (settings.protected === false) { + worksheet.unprotect(); + return; + } + // Translate raw OOXML "blocked" flags into ExcelJS "allowed" options. + const options = {}; + const allowed = (key, flag) => { + if (settings[flag] !== null && settings[flag] !== undefined) { + options[key] = !settings[flag]; + } + }; + allowed("formatCells", "format_cells"); + allowed("insertRows", "insert_rows"); + allowed("selectLockedCells", "select_locked_cells"); + allowed("selectUnlockedCells", "select_unlocked_cells"); + allowed("sort", "sort"); + allowed("autoFilter", "auto_filter"); + await worksheet.protect(settings.password || "", options); +} + +function writePageSetup(worksheet, settings) { + if (settings.orientation) worksheet.pageSetup.orientation = settings.orientation; + const fitWidth = settings.fit_to_width; + const fitHeight = settings.fit_to_height; + if (isNumber(fitWidth) || isNumber(fitHeight)) { + worksheet.pageSetup.fitToPage = true; + if (isNumber(fitWidth)) worksheet.pageSetup.fitToWidth = fitWidth; + if (isNumber(fitHeight)) worksheet.pageSetup.fitToHeight = fitHeight; + } + if (isNumber(settings.scale)) worksheet.pageSetup.scale = settings.scale; + if (settings.print_title_rows) { + worksheet.pageSetup.printTitlesRow = String(settings.print_title_rows).replace(/\$/g, ""); + } + if (settings.header_center) worksheet.headerFooter.oddHeader = `&C${settings.header_center}`; + if (settings.footer_center) worksheet.headerFooter.oddFooter = `&C${settings.footer_center}`; +} + +// =========================================================================== +// mutate +// =========================================================================== + +async function mutate(request) { + const inputPath = requirePath(request, "input_path", "mutate"); + const outputPath = requirePath(request, "output_path", "mutate"); + const mutations = (request.payload && request.payload.mutations) || []; + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.readFile(inputPath); + for (const mutation of mutations) { + sheetOf(workbook, mutation.sheet).getCell(mutation.cell).value = mutation.value ?? null; + } + await fs.mkdir(path.dirname(path.resolve(outputPath)), { recursive: true }); + await workbook.xlsx.writeFile(outputPath); + return { written: outputPath }; +} + +// =========================================================================== +// helpers +// =========================================================================== + +function requirePath(request, key, operation) { + if (!request[key]) throw new Error(`${operation} requires ${key}.`); + return request[key]; +} + +function sheetOf(workbook, name) { + const worksheet = workbook.getWorksheet(name); + if (!worksheet) throw new Error(`Sheet not found: ${name}`); + return worksheet; +} + +function noteText(note) { + if (typeof note === "string") return note; + return (note.texts || []).map((run) => run.text).join(""); +} + +function argbToHex(color) { + if (!color || typeof color.argb !== "string") return null; + const argb = color.argb.toUpperCase(); + if (argb.length === 8) return `#${argb.slice(2)}`; + if (argb.length === 6) return `#${argb}`; + return null; +} + +function hexToArgb(hex) { + const stripped = String(hex).replace(/^#/, "").toUpperCase(); + return stripped.length === 6 ? `FF${stripped}` : stripped; +} + +function stripEquals(text) { + return String(text).replace(/^=/, ""); +} + +function isNumber(value) { + return typeof value === "number" && Number.isFinite(value); +} + +function columnLetter(index) { + let n = index; + let letters = ""; + while (n > 0) { + const rem = (n - 1) % 26; + letters = String.fromCharCode(65 + rem) + letters; + n = Math.floor((n - 1) / 26); + } + return letters; +} + +function decodeCell(address) { + const match = /^\$?([A-Za-z]+)\$?(\d+)$/.exec(String(address)); + if (!match) throw new Error(`Invalid cell address '${address}'.`); + let col = 0; + for (const ch of match[1].toUpperCase()) col = col * 26 + (ch.charCodeAt(0) - 64); + return { col, row: Number(match[2]) }; +} + +function decodeRange(ref) { + const [start, end] = String(ref).split(":"); + const a = decodeCell(start); + const b = decodeCell(end || start); + return { + left: Math.min(a.col, b.col), + right: Math.max(a.col, b.col), + top: Math.min(a.row, b.row), + bottom: Math.max(a.row, b.row), + }; +} + +// Pixel size of a PNG or JPEG buffer, needed for ExcelJS oneCell `ext`. +function imagePixelSize(buffer, extension) { + if (extension === "png") { + if (buffer.length < 24 || buffer.readUInt32BE(12) !== 0x49484452) { + throw new Error("Malformed PNG: missing IHDR chunk."); + } + return { width: buffer.readUInt32BE(16), height: buffer.readUInt32BE(20) }; + } + if (extension === "jpeg") { + let offset = 2; + while (offset + 9 < buffer.length) { + if (buffer[offset] !== 0xff) { + offset += 1; + continue; + } + const marker = buffer[offset + 1]; + const length = buffer.readUInt16BE(offset + 2); + const isFrame = + marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc; + if (isFrame) { + return { width: buffer.readUInt16BE(offset + 7), height: buffer.readUInt16BE(offset + 5) }; + } + offset += 2 + length; + } + throw new Error("Malformed JPEG: no frame header."); + } + throw new Error(`Cannot size '${extension}' image for a oneCell anchor.`); +} + +module.exports = { describe, readModel, writeModel, mutate }; diff --git a/tools/external-oracles/exceljs/exceljs-oracle.cjs b/tools/external-oracles/exceljs/exceljs-oracle.cjs index 592f405..6fc61b1 100644 --- a/tools/external-oracles/exceljs/exceljs-oracle.cjs +++ b/tools/external-oracles/exceljs/exceljs-oracle.cjs @@ -6,6 +6,13 @@ let JSZip; const PIXEL_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII="; +const MODEL_OPERATIONS = { + describe: "describe", + read_model: "readModel", + write_model: "writeModel", + mutate: "mutate", +}; + main().catch((error) => { process.stdout.write( `${JSON.stringify({ error: "exceljs_oracle_failed", message: error.message })}\n`, @@ -21,7 +28,9 @@ async function main() { ? await writeFixture(request) : request.operation === "read_metadata" ? await readMetadata(request) - : fail(`Unsupported operation '${request.operation}'.`); + : request.operation in MODEL_OPERATIONS + ? await require("./exceljs-model.cjs")[MODEL_OPERATIONS[request.operation]](request) + : fail(`Unsupported operation '${request.operation}'.`); process.stdout.write(`${JSON.stringify(payload)}\n`); } diff --git a/tools/external-oracles/libreoffice/README.md b/tools/external-oracles/libreoffice/README.md index c78b08c..45c2df8 100644 --- a/tools/external-oracles/libreoffice/README.md +++ b/tools/external-oracles/libreoffice/README.md @@ -1,23 +1,163 @@ -# LibreOffice External Oracle +# LibreOffice helpers -Optional helper for validating `.xlsx` workbooks through LibreOffice Calc in -headless mode. It is a renderer/open-save oracle, not a normal benchmark -adapter. +Two independent helpers live here: -## Run +- `libreoffice_uno_adapter.py` + `uno/excelbench_uno.py`: the `libreoffice` + benchmark adapter (read, write, modify) used by + `excelbench.harness.adapters.libreoffice_adapter` and + `excelbench.modifiable.LibreofficeEngine`. +- `libreoffice_oracle.py`: the older open/save and render oracle (not a + benchmark adapter). + +Both locate LibreOffice through `LIBREOFFICE_BIN`, `soffice`, `libreoffice`, or +`/Applications/LibreOffice.app/Contents/MacOS/soffice`. + +## Benchmark adapter (`libreoffice`) + +### Run + +```bash +cd tools/external-oracles/libreoffice +python libreoffice_uno_adapter.py < request.json +``` + +The request/response protocol is the ExcelBench JSON-model helper protocol +(`describe`, `read_model`, `write_model`, `mutate`) documented in +`src/excelbench/harness/adapters/json_model_adapter.py`. Any Python 3 works for +the launcher; ExcelBench runs it with its own interpreter. + +### Why a macro inside soffice + +The obvious designs do not work on macOS arm64 with LibreOffice 26.8: + +- LibreOffice's bundled standalone interpreter + (`LibreOffice.app/Contents/Resources/python`) is killed with SIGKILL on + launch. +- Importing `uno` from a regular Python interpreter segfaults. + +What does work is LibreOffice's embedded Python running a user macro inside +`soffice` itself. The launcher therefore: + +1. Reads one JSON request from stdin and writes it to a temporary file. +2. Resolves `soffice` (order above). +3. Takes an exclusive file lock on a reusable profile directory + (`$XDG_CACHE_HOME/excelbench/libreoffice-uno/profile`, default + `~/.cache/...`; override with `EXCELBENCH_LIBREOFFICE_PROFILE`). Two soffice + processes on one profile do not run side by side: the second forwards its + arguments to the first over IPC and exits, so concurrent requests would + silently never run. The lock serializes them. +4. Copies `uno/excelbench_uno.py` into `/user/Scripts/python/` on every + run, so the macro always matches the checkout. +5. Runs + `soffice -env:UserInstallation= --headless --invisible --norestore --nologo --nodefault --nolockcheck 'vnd.sun.star.script:excelbench_uno.py$main?language=Python&location=user'` + with the request and response file paths in `EXCELBENCH_UNO_REQUEST` and + `EXCELBENCH_UNO_RESPONSE`. The default timeout is 150 s + (`EXCELBENCH_LIBREOFFICE_TIMEOUT` overrides it); on timeout the whole + process group is killed. +6. Prints the macro's JSON response. If soffice exits without writing one, it + prints `{"error": "libreoffice_failed", ...}` with the soffice return code + and stderr tail and exits 1. + +The first launch with a fresh profile takes about 5 s; a warm profile opens, +reads, and closes a fixture in about 3 to 4 s. Every operation is one soffice +process. + +### Version recording + +`describe` reads `ooSetupVersionAboutBox` (plus `ooSetupVersionAboutBoxSuffix`) +from the `/org.openoffice.Setup/Product` configuration node and the `buildid` +from the installation's `versionrc` via the UNO macro expander, for example +`26.8.0.3 (build bce0998afefdbc355585ca324285661a2170ba77)`. + +### Read path + +`read_model` opens the workbook with `loadComponentFromURL` (`Hidden=True`), so +every value is what Calc's OOXML import produced, then walks the Calc UNO API. +No workbook XML is parsed. Conversions that are not plain property reads: + +- Formulas, defined names, conditional-format and validation formulas, and + internal hyperlink targets are Calc token arrays or Calc-grammar strings, + printed through `com.sun.star.sheet.FormulaParser` with the OOXML op-code map + and the `XL_OOX` address convention. +- A formula cell whose result is an error reports `type: "error"` with the + error text (contract rule). Calc recalculates on import; for example the + fixture formula `=A3*2` over a text cell reads as `#VALUE!`. +- Calc imports OOXML boolean cells as `=TRUE()` / `=FALSE()` formula cells, and + the API reports them as formulas, so that is what the adapter reports. +- Date cells: numeric cells whose number format type is DATE, converted with the + document `NullDate`. +- Row height: Calc stores twips; points = round(height_hmm * 1440 / 2540) / 20. + Only rows without `OptimalHeight` are reported. +- Column width: `Width` (1/100 mm) divided by the widest digit of the workbook + default font (`Default` cell style, measured on the document reference device + as `XclRoot::SetCharWidth` does), truncated to two decimals as + `XclExpColinfo::SaveXml` writes it. A 20.83203125 OOXML width therefore reads + as 20.83, and after ExcelBench strips the Excel padding, 19.998. +- Borders: `TopBorder2`... `DiagonalTLBR2` mapped to OOXML styles with the + width thresholds of `lclGetBorderLine` in `sc/source/filter/excel/xestyle.cxx`. +- Rotation and indent: `XclTools::GetXclRotation` and the export's + `(twips + 100) / 200` indent level. +- Conditional format kinds are classified by the properties each entry object + exposes (the numeric `getType()` codes are not consistent across entry + implementations). +- Explicit validation lists (`"Red";"Green";"Blue"` in Calc) are reported as one + quoted comma-joined literal, which is how Calc's xlsx export writes them. +- Chart and image `from` cells come from the shape `Anchor`; the chart `to` cell + is the cell holding the shape's bottom-right point using Calc's own cell + positions, with a point on a boundary assigned to the preceding cell. That is + the `xdr:to` Calc's xlsx export writes for the same shape. +- Freeze panes come from the controller (`hasFrozenPanes`, `getSplitColumn`, + `getSplitRow`); non-frozen splits come from the document view settings. +- Sheet protection: `XProtectable.isProtected()`. Whether a password is set is + probed with `unprotect("")` (it succeeds only without a password) after every + other read of that sheet. + +### Write path + +`write_model` creates a Calc document (not `Hidden`: soffice already runs +headless, and with `Hidden=True` Calc silently drops view operations such as +`freezeAtPosition`), inserts the requested sheets, removes the default sheet, +replays each op through the UNO API, and stores with the `Calc Office Open XML` +filter. Number formats are registered under the document default locale; an +explicit locale makes the export prefix codes with `[$-409]`. `mutate` loads the +template, sets values with `setString` / `setValue`, and stores the same way. + +### Unsupported declarations + +`describe.unsupported_write` and `model.unsupported` are both empty: Calc's UNO +API can read and write every one of the 22 benchmark features at least in part. +The gaps below are specific attributes; they are not filled in or faked, so the +affected test cases fail. + +| Area | Gap | Reason | +| --- | --- | --- | +| Hyperlinks | `tooltip` is always null (read and write) | Calc's URL text field (`com.sun.star.text.TextField.URL`) has no ScreenTip property. | +| Conditional formatting | `priority` and `stop_if_true` are null (read) and not written | Calc's conditional-format API has neither concept; entries are evaluated in insertion order. | +| Conditional formatting | color scale rules are not written | `createEntry(COLORSCALE)` yields a format with zero scale entries, and setting `ColorScaleEntries` indexes existing entries without adding them (`ScColorScaleFormatObj`), which aborts soffice with SIGABRT. No other UNO call adds scale entries. | +| Sheet protection | granular flags (`format_cells`, `insert_rows`, `select_locked_cells`, `select_unlocked_cells`, `sort`, `auto_filter`) are null on read and not written | `XProtectable` exposes only `protect(password)`, `unprotect(password)`, and `isProtected()`. | +| Freeze panes | non-frozen splits do not survive a write | `XViewSplitable.splitAtPosition` takes pixels (OOXML split offsets are twips, so small offsets round to 0 px), and Calc's own xlsx round-trip also drops split panes. Frozen panes work. | +| Comments | `author` is not written | `XSheetAnnotation.Author` is read-only; new notes carry the profile's user name. | +| Pivot tables | `target_cell` reads Calc's `OutputRange` start | That is the cell Calc reports for the pivot output; no other location is exposed. | + +LibreOffice behaviors that surface as failed cases (observed, not adapter gaps): +OOXML booleans import as `TRUE()`/`FALSE()` formulas; number format codes are +reported in Calc's dialect (`YYYY-MM-DD`) and exported with Calc's escaping +(`\$#,##0.00`, `"USD "0.00`); conditional-format fills are exported as a +`patternFill` with only `bgColor`; references to undefined names are +lowercased; a header-only table range is not exported; fit-to-page values are +ignored without the `fitToPage` flag and the export always writes `scale` and +`fitToWidth`/`fitToHeight`; the drawing `to` anchor of a shape whose end lies on +a cell boundary is written as the preceding cell plus a full-size offset. + +## Open/save and render oracle (`libreoffice_oracle.py`) ```bash python libreoffice_oracle.py < request.json ``` -The helper locates LibreOffice through `LIBREOFFICE_BIN`, `soffice`, -`libreoffice`, or `/Applications/LibreOffice.app/Contents/MacOS/soffice`. Missing LibreOffice returns a structured skip. -## Operations - - `open_save_validate`: converts an input workbook back to `.xlsx` using the `Calc Office Open XML` filter. - `render_validate` / `render_pdf`: exports an input workbook to PDF using the `calc_pdf_Export` filter. - diff --git a/tools/external-oracles/libreoffice/libreoffice_uno_adapter.py b/tools/external-oracles/libreoffice/libreoffice_uno_adapter.py new file mode 100755 index 0000000..b1ae093 --- /dev/null +++ b/tools/external-oracles/libreoffice/libreoffice_uno_adapter.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python3 +"""Host launcher for the LibreOffice Calc JSON-model adapter helper. + +Reads one ExcelBench helper request (JSON) on stdin, runs the +``uno/excelbench_uno.py`` macro inside ``soffice --headless`` (LibreOffice's +own embedded Python interpreter), and prints the macro's JSON response on +stdout. Only the Python standard library is used on the host side; every +spreadsheet operation happens inside soffice through the UNO API. + +Why a macro instead of a UNO socket bridge: on macOS the bundled standalone +``Contents/Resources/python`` is SIGKILLed by the OS and importing ``uno`` from +a foreign Python segfaults. A Python macro stored in the user profile runs in +soffice's embedded interpreter and needs neither. +""" + +from __future__ import annotations + +import json +import os +import shutil +import signal +import subprocess +import sys +import tempfile +from pathlib import Path +from typing import Any + +JSONDict = dict[str, Any] + +HELPER_DIR = Path(__file__).resolve().parent +MACRO_SOURCE = HELPER_DIR / "uno" / "excelbench_uno.py" +MACRO_NAME = "excelbench_uno.py" +MACRO_URL = f"vnd.sun.star.script:{MACRO_NAME}$main?language=Python&location=user" +REQUEST_ENV = "EXCELBENCH_UNO_REQUEST" +RESPONSE_ENV = "EXCELBENCH_UNO_RESPONSE" +DEFAULT_TIMEOUT_SECONDS = 150.0 +STDERR_TAIL_CHARS = 4000 + + +def main() -> int: + try: + request = json.load(sys.stdin) + if not isinstance(request, dict): + raise ValueError("request must be a JSON object") + response = run_request(request) + except Exception as exc: # pragma: no cover - last-resort CLI guard + response = { + "error": "libreoffice_failed", + "message": f"{type(exc).__name__}: {exc}", + } + print(json.dumps(response, sort_keys=True)) + return 1 if response.get("error") else 0 + + +def resolve_soffice() -> str | None: + """Find soffice the same way the Python adapter does.""" + for candidate in ( + os.environ.get("LIBREOFFICE_BIN"), + shutil.which("soffice"), + shutil.which("libreoffice"), + "/Applications/LibreOffice.app/Contents/MacOS/soffice", + ): + if candidate and Path(candidate).exists(): + return str(candidate) + return None + + +def profile_root() -> Path: + """Return the reusable LibreOffice profile directory (outside the repo).""" + override = os.environ.get("EXCELBENCH_LIBREOFFICE_PROFILE") + if override: + return Path(override).expanduser().resolve() + cache = os.environ.get("XDG_CACHE_HOME") or str(Path.home() / ".cache") + return Path(cache).expanduser().resolve() / "excelbench" / "libreoffice-uno" / "profile" + + +class ProfileLock: + """Exclusive lock serializing soffice runs that share one user profile. + + Two soffice processes on one ``UserInstallation`` do not run side by side: + the second hands its arguments to the first over IPC and exits, so a + concurrent request would silently never execute. The lock prevents that. + """ + + def __init__(self, path: Path) -> None: + self.path = path + self._handle: Any = None + + def __enter__(self) -> ProfileLock: + self.path.parent.mkdir(parents=True, exist_ok=True) + self._handle = open(self.path, "a+b") # noqa: SIM115 - held for the lock lifetime + if os.name == "nt": + import msvcrt + + self._handle.seek(0) + msvcrt.locking(self._handle.fileno(), msvcrt.LK_LOCK, 1) + else: + import fcntl + + fcntl.flock(self._handle.fileno(), fcntl.LOCK_EX) + return self + + def __exit__(self, *_exc: object) -> None: + if self._handle is None: + return + if os.name == "nt": + import msvcrt + + self._handle.seek(0) + msvcrt.locking(self._handle.fileno(), msvcrt.LK_UNLCK, 1) + else: + import fcntl + + fcntl.flock(self._handle.fileno(), fcntl.LOCK_UN) + self._handle.close() + self._handle = None + + +def install_macro(profile: Path) -> None: + """Copy the macro into ``/user/Scripts/python`` for this run.""" + target_dir = profile / "user" / "Scripts" / "python" + target_dir.mkdir(parents=True, exist_ok=True) + shutil.copyfile(MACRO_SOURCE, target_dir / MACRO_NAME) + + +def timeout_seconds() -> float: + raw = os.environ.get("EXCELBENCH_LIBREOFFICE_TIMEOUT") + if raw: + try: + return max(1.0, float(raw)) + except ValueError: + pass + return DEFAULT_TIMEOUT_SECONDS + + +def _stderr_tail(stderr: str) -> str: + stderr = stderr.strip() + return stderr[-STDERR_TAIL_CHARS:] if len(stderr) > STDERR_TAIL_CHARS else stderr + + +def _kill_group(process: subprocess.Popen[str]) -> None: + """Kill soffice and anything it spawned so the profile is released.""" + try: + if os.name == "nt": + process.kill() + else: + os.killpg(process.pid, signal.SIGKILL) + except (ProcessLookupError, PermissionError): + pass + + +def run_request(request: JSONDict) -> JSONDict: + if not MACRO_SOURCE.is_file(): + return { + "error": "libreoffice_failed", + "message": f"macro not found: {MACRO_SOURCE}", + } + soffice = resolve_soffice() + if soffice is None: + return { + "error": "libreoffice_failed", + "message": "LibreOffice soffice executable not found " + "(set LIBREOFFICE_BIN or put soffice on PATH)", + } + + profile = profile_root() + limit = timeout_seconds() + with tempfile.TemporaryDirectory(prefix="excelbench-uno-") as tmp: + request_path = Path(tmp) / "request.json" + response_path = Path(tmp) / "response.json" + request_path.write_text(json.dumps(request), encoding="utf-8") + env = os.environ.copy() + env[REQUEST_ENV] = str(request_path) + env[RESPONSE_ENV] = str(response_path) + command = [ + soffice, + f"-env:UserInstallation={profile.as_uri()}", + "--headless", + "--invisible", + "--norestore", + "--nologo", + "--nodefault", + "--nolockcheck", + MACRO_URL, + ] + with ProfileLock(profile.parent / f"{profile.name}.lock"): + install_macro(profile) + process = subprocess.Popen( + command, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + env=env, + start_new_session=os.name != "nt", + ) + try: + stdout, stderr = process.communicate(timeout=limit) + except subprocess.TimeoutExpired: + _kill_group(process) + stdout, stderr = process.communicate() + return { + "error": "libreoffice_failed", + "message": f"soffice did not finish {request.get('operation')!r} " + f"within {limit:g}s", + "stderr": _stderr_tail(stderr or ""), + } + + if response_path.is_file(): + try: + response = json.loads(response_path.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + return { + "error": "libreoffice_failed", + "message": f"macro wrote invalid JSON: {exc}", + "stderr": _stderr_tail(stderr or ""), + } + if isinstance(response, dict): + return response + return { + "error": "libreoffice_failed", + "message": "macro response is not an object", + } + + return { + "error": "libreoffice_failed", + "message": "soffice exited without running the ExcelBench macro " + f"(returncode {process.returncode})", + "stdout": (stdout or "").strip()[-STDERR_TAIL_CHARS:], + "stderr": _stderr_tail(stderr or ""), + } + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/external-oracles/libreoffice/uno/excelbench_uno.py b/tools/external-oracles/libreoffice/uno/excelbench_uno.py new file mode 100644 index 0000000..6a229c3 --- /dev/null +++ b/tools/external-oracles/libreoffice/uno/excelbench_uno.py @@ -0,0 +1,2027 @@ +# ruff: noqa: N802, N815, N816 +"""ExcelBench JSON-model helper executed inside LibreOffice's embedded Python. + +``libreoffice_uno_adapter.py`` copies this module into +``/user/Scripts/python`` and launches:: + + soffice --headless ... \ + 'vnd.sun.star.script:excelbench_uno.py$main?language=Python&location=user' + +The request and response file paths arrive through the +``EXCELBENCH_UNO_REQUEST`` / ``EXCELBENCH_UNO_RESPONSE`` environment +variables. Every value reported here comes from the Calc UNO API after +LibreOffice's own OOXML import; nothing parses workbook XML. + +Unit conversions mirror what Calc's own xlsx export does with the same data, +so a value reported here is the value LibreOffice would write back: + +* row height: Calc stores twips; UNO reports 1/100 mm. Points = + round(hmm * 1440 / 2540) / 20. +* column width: UNO 1/100 mm divided by the width of the widest digit of the + workbook default font (the ``Default`` cell style font measured on the + document reference device, as ``XclRoot::SetCharWidth`` does), truncated to + two decimals (``XclExpColinfo::SaveXml``). +* borders: (line style, outer width in twips, double-line distance) mapped to + OOXML border styles with the thresholds of ``lclGetBorderLine`` in + ``sc/source/filter/excel/xestyle.cxx``. +* text rotation: ``XclTools::GetXclRotation``. +* formulas, defined names, CF/DV formulas, internal hyperlink targets: Calc + formula tokens printed through ``com.sun.star.sheet.FormulaParser`` with + the OOXML op-code map and the XL_OOX address convention. +""" + +from __future__ import annotations + +import json +import os +import traceback +from datetime import datetime, timedelta + +import uno +import unohelper +from com.sun.star.awt import FontDescriptor, Point, Rectangle, Size +from com.sun.star.beans import PropertyValue +from com.sun.star.lang import Locale +from com.sun.star.sheet import XDataBarEntry +from com.sun.star.table import BorderLine2, CellAddress, CellRangeAddress + +LIBRARY = "libreoffice" +REQUEST_ENV = "EXCELBENCH_UNO_REQUEST" +RESPONSE_ENV = "EXCELBENCH_UNO_RESPONSE" +XLSX_FILTER = "Calc Office Open XML" +CHART_CLSID = "12DCAE26-281F-416F-A234-C3086127382E" + +# Minimum scan window for row heights / column widths. Calc reports a height +# and width for every row and column, so custom dimensions are found by +# scanning rows/columns up to max(used area, these bounds). +MIN_SCAN_ROWS = 100 +MIN_SCAN_COLS = 26 + +HMM_PER_TWIP = 2540.0 / 1440.0 +EMU_PER_HMM = 360 + +# Write ops whose content the Calc UNO API cannot express at all. +UNSUPPORTED_WRITE: dict[str, str] = {} + + +def _const(name): + return uno.getConstantByName(name) + + +def _enum(type_name, value): + return uno.Enum(type_name, value) + + +def pv(name, value): + prop = PropertyValue() + prop.Name = name + prop.Value = value + return prop + + +# ============================================================================= +# Entry point +# ============================================================================= + + +def main(*_args): + response_path = os.environ.get(RESPONSE_ENV) + try: + with open(os.environ[REQUEST_ENV], encoding="utf-8") as handle: + request = json.load(handle) + response = Helper(XSCRIPTCONTEXT).handle(request) # noqa: F821 + except Exception as exc: + message = getattr(exc, "Message", None) or str(exc) + response = { + "error": "libreoffice_failed", + "message": f"{type(exc).__name__}: {message}", + "traceback": traceback.format_exc(), + } + if response_path: + with open(response_path, "w", encoding="utf-8") as handle: + json.dump(response, handle, sort_keys=True) + + +g_exportedScripts = (main,) + + +# ============================================================================= +# Address helpers +# ============================================================================= + + +def col_letter(index): + """0-based column index -> letters.""" + index += 1 + letters = "" + while index > 0: + index, rem = divmod(index - 1, 26) + letters = chr(65 + rem) + letters + return letters + + +def a1(col, row): + return f"{col_letter(col)}{row + 1}" + + +def a1_range(addr): + start = a1(addr.StartColumn, addr.StartRow) + end = a1(addr.EndColumn, addr.EndRow) + return start if start == end else f"{start}:{end}" + + +def parse_a1(ref): + """'B12' or '$B$12' -> (col, row) 0-based.""" + ref = ref.replace("$", "").strip().upper() + col = 0 + i = 0 + while i < len(ref) and ref[i].isalpha(): + col = col * 26 + (ord(ref[i]) - 64) + i += 1 + if i == 0 or i == len(ref): + raise ValueError(f"invalid cell reference {ref!r}") + return col - 1, int(ref[i:]) - 1 + + +def parse_a1_range(ref): + ref = ref.split("!")[-1] + if ":" in ref: + start, end = ref.split(":", 1) + else: + start = end = ref + c1, r1 = parse_a1(start) + c2, r2 = parse_a1(end) + return c1, r1, c2, r2 + + +def color_hex(value): + if value is None or value == -1: + return None + return f"#{value & 0xFFFFFF:06X}" + + +def color_int(hex_color): + return int(str(hex_color).lstrip("#")[-6:], 16) + + +def to_json_number(value): + if isinstance(value, float) and value.is_integer() and abs(value) < 2**53: + return int(value) + return value + + +# ============================================================================= +# Helper +# ============================================================================= + + +class Helper: + def __init__(self, script_context): + self.script_context = script_context + self.ctx = script_context.getComponentContext() + self.smgr = self.ctx.ServiceManager + self.desktop = script_context.getDesktop() + + def create(self, service): + return self.smgr.createInstanceWithContext(service, self.ctx) + + # ------------------------------------------------------------------ dispatch + + def handle(self, request): + operation = request.get("operation") + if operation == "describe": + return self.describe() + if operation == "read_model": + return {"model": self.read_model(self._input_path(request))} + if operation == "write_model": + output = self._output_path(request) + ops = (request.get("payload") or {}).get("ops") or [] + self.write_model(ops, output) + return {"written": output} + if operation == "mutate": + output = self._output_path(request) + mutations = (request.get("payload") or {}).get("mutations") or [] + self.mutate(self._input_path(request), mutations, output) + return {"written": output} + return { + "error": "libreoffice_failed", + "message": f"unsupported operation {operation!r}", + } + + @staticmethod + def _input_path(request): + path = request.get("input_path") + if not path or not os.path.isfile(path): + raise ValueError(f"input_path does not exist: {path!r}") + return os.path.abspath(path) + + @staticmethod + def _output_path(request): + path = request.get("output_path") + if not path: + raise ValueError("output_path is required") + path = os.path.abspath(path) + os.makedirs(os.path.dirname(path), exist_ok=True) + return path + + # ------------------------------------------------------------------ describe + + def describe(self): + return { + "library": LIBRARY, + "version": self.product_version(), + "capabilities": ["read", "write", "modify"], + "unsupported_write": dict(UNSUPPORTED_WRITE), + } + + def product_version(self): + provider = self.create("com.sun.star.configuration.ConfigurationProvider") + access = provider.createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + (pv("nodepath", "/org.openoffice.Setup/Product"),), + ) + version = str(access.getByName("ooSetupVersionAboutBox")) + if access.hasByName("ooSetupVersionAboutBoxSuffix"): + suffix = access.getByName("ooSetupVersionAboutBoxSuffix") + if suffix: + version = f"{version}{suffix}" + build_id = self.build_id() + return f"{version} (build {build_id})" if build_id else version + + def build_id(self): + try: + expander = self.ctx.getValueByName("/singletons/com.sun.star.util.theMacroExpander") + except Exception: + return None + for rc in ("Resources/versionrc", "program/versionrc", "program/version.ini"): + try: + value = expander.expandMacros(f"${{$BRAND_BASE_DIR/{rc}:buildid}}") + except Exception: + continue + if value and "$" not in value and "<" not in value: + return value + return None + + # ------------------------------------------------------------------ documents + + def load(self, path): + url = uno.systemPathToFileUrl(path) + doc = self.desktop.loadComponentFromURL( + url, "_blank", 0, (pv("Hidden", True), pv("ReadOnly", False)) + ) + if doc is None: + raise RuntimeError(f"LibreOffice could not load {path}") + return doc + + def new_document(self): + # Not Hidden: soffice already runs --headless, and Calc applies view + # operations such as freezeAtPosition only to a document whose view + # has a (headless) window; with Hidden=True they are silently dropped. + doc = self.desktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, ()) + if doc is None: + raise RuntimeError("LibreOffice could not create a Calc document") + return doc + + @staticmethod + def store_xlsx(doc, path): + doc.storeToURL( + uno.systemPathToFileUrl(path), + (pv("FilterName", XLSX_FILTER), pv("Overwrite", True)), + ) + if not os.path.isfile(path): + raise RuntimeError(f"LibreOffice did not write {path}") + + @staticmethod + def close(doc): + try: + doc.close(True) + except Exception: + doc.dispose() + + # ------------------------------------------------------------------ read + + def read_model(self, path): + doc = self.load(path) + try: + return ModelReader(self, doc).read() + finally: + self.close(doc) + + # ------------------------------------------------------------------ write + + def write_model(self, ops, output): + doc = self.new_document() + try: + OpWriter(self, doc).apply(ops) + self.store_xlsx(doc, output) + finally: + self.close(doc) + + def mutate(self, path, mutations, output): + doc = self.load(path) + try: + for mutation in mutations: + sheet_name = mutation["sheet"] + if not doc.Sheets.hasByName(sheet_name): + raise KeyError(f"sheet not found: {sheet_name}") + sheet = doc.Sheets.getByName(sheet_name) + col, row = parse_a1(mutation["cell"]) + set_plain_value(doc, sheet.getCellByPosition(col, row), mutation["value"]) + self.store_xlsx(doc, output) + finally: + self.close(doc) + + +def set_plain_value(doc, cell, value): + """Set a str/int/float/bool through the cell API (template mutation lane).""" + if value is None: + cell.setString("") + cell.setFormula("") + elif isinstance(value, bool): + cell.setValue(1.0 if value else 0.0) + cell.NumberFormat = standard_format(doc, "LOGICAL") + elif isinstance(value, (int, float)): + cell.setValue(float(value)) + else: + cell.setString(str(value)) + + +def standard_format(doc, kind): + return doc.NumberFormats.getStandardFormat( + _const(f"com.sun.star.util.NumberFormat.{kind}"), Locale() + ) + + +# ============================================================================= +# Formula grammar bridge +# ============================================================================= + + +class Grammar: + """Converts between Calc token arrays and OOXML / Calc formula strings.""" + + def __init__(self, doc): + mapper = doc.createInstance("com.sun.star.sheet.FormulaOpCodeMapper") + groups = 0 + for group in ( + "SPECIAL", + "SEPARATORS", + "ARRAY_SEPARATORS", + "UNARY_OPERATORS", + "BINARY_OPERATORS", + "FUNCTIONS", + ): + groups |= _const(f"com.sun.star.sheet.FormulaMapGroup.{group}") + language = "com.sun.star.sheet.FormulaLanguage." + convention = "com.sun.star.sheet.AddressConvention." + + def make(lang, conv): + parser = doc.createInstance("com.sun.star.sheet.FormulaParser") + parser.FormulaConvention = _const(convention + conv) + parser.OpCodeMap = mapper.getAvailableMappings(_const(language + lang), groups) + return parser + + # OOXML: Excel function names, ',' separators, Sheet!A1 references. + self.ooxml = make("OOXML", "XL_OOX") + # Calc API grammar: English names, ';' separators, $Sheet.A1 references. + self.api = make("ENGLISH", "OOO") + # UI grammar used by the new conditional-format entry API. + self.native = make("NATIVE", "OOO") + + def tokens_to_ooxml(self, tokens, base): + return self.ooxml.printFormula(tokens, base) + + def calc_to_ooxml(self, text, base, native=False): + parser = self.native if native else self.api + return self.ooxml.printFormula(parser.parseFormula(text, base), base) + + def ooxml_to_tokens(self, text, base): + return self.ooxml.parseFormula(text, base) + + def ooxml_to_calc(self, text, base, native=False): + parser = self.native if native else self.api + return parser.printFormula(self.ooxml.parseFormula(text, base), base) + + +def strip_eq(text): + text = str(text).strip() + return text[1:] if text.startswith("=") else text + + +# ============================================================================= +# Read side +# ============================================================================= + +UNDERLINE_NAMES = { + 1: "single", + 2: "double", + 3: "dotted", + 5: "dash", + 6: "longDash", + 7: "dashDot", + 8: "dashDotDot", + 9: "smallWave", + 10: "wave", + 11: "doubleWave", + 12: "bold", + 13: "boldDotted", + 14: "boldDash", + 15: "boldLongDash", + 16: "boldDashDot", + 17: "boldDashDotDot", + 18: "boldWave", +} +H_ALIGN_NAMES = { + "LEFT": "left", + "CENTER": "center", + "RIGHT": "right", + "BLOCK": "justify", + "REPEAT": "fill", +} +V_ALIGN_NAMES = {1: "top", 2: "center", 3: "bottom", 4: "justify"} + +# Twip thresholds of lclGetBorderLine (EXC_BORDER_THICK/MEDIUM/THIN/HAIR). +BORDER_THICK_TWIPS = 50 +BORDER_MEDIUM_TWIPS = 35 +BORDER_THIN_TWIPS = 15 +BORDER_HAIR_TWIPS = 1 + +# com.sun.star.table.BorderLineStyle +BLS_NONE = 0x7FFF +BLS_SOLID = 0 +BLS_DOTTED = 1 +BLS_DASHED = 2 +BLS_DOUBLE = 3 +BLS_FINE_DASHED = 14 +BLS_DOUBLE_THIN = 15 +BLS_DASH_DOT = 16 +BLS_DASH_DOT_DOT = 17 + +# com.sun.star.sheet.ConditionFormatOperator -> (rule_type, operator) +CF_OPERATORS = { + 0: ("cellIs", "equal"), + 1: ("cellIs", "lessThan"), + 2: ("cellIs", "greaterThan"), + 3: ("cellIs", "lessThanOrEqual"), + 4: ("cellIs", "greaterThanOrEqual"), + 5: ("cellIs", "notEqual"), + 6: ("cellIs", "between"), + 7: ("cellIs", "notBetween"), + 8: ("duplicateValues", None), + 9: ("uniqueValues", None), + 10: ("containsErrors", None), + 11: ("notContainsErrors", None), + 12: ("beginsWith", None), + 13: ("endsWith", None), + 14: ("containsText", None), + 15: ("notContainsText", None), + 16: ("top10", None), + 17: ("top10", None), + 18: ("top10", None), + 19: ("top10", None), + 20: ("aboveAverage", None), + 21: ("aboveAverage", None), + 22: ("aboveAverage", None), + 23: ("aboveAverage", None), + 24: ("expression", None), +} + +DV_TYPES = { + "WHOLE": "whole", + "DECIMAL": "decimal", + "DATE": "date", + "TIME": "time", + "TEXT_LEN": "textLength", + "LIST": "list", + "CUSTOM": "custom", +} +CONDITION_OPERATORS = { + "EQUAL": "equal", + "NOT_EQUAL": "notEqual", + "GREATER": "greaterThan", + "GREATER_EQUAL": "greaterThanOrEqual", + "LESS": "lessThan", + "LESS_EQUAL": "lessThanOrEqual", + "BETWEEN": "between", + "NOT_BETWEEN": "notBetween", +} + +CHART_TYPES = { + "com.sun.star.chart2.ColumnChartType": "bar", + "com.sun.star.chart2.BarChartType": "bar", + "com.sun.star.chart2.LineChartType": "line", + "com.sun.star.chart2.PieChartType": "pie", + "com.sun.star.chart2.AreaChartType": "area", + "com.sun.star.chart2.ScatterChartType": "scatter", + "com.sun.star.chart2.BubbleChartType": "bubble", + "com.sun.star.chart2.NetChartType": "radar", + "com.sun.star.chart2.FilledNetChartType": "radar", + "com.sun.star.chart2.CandleStickChartType": "stock", +} + +ACTIVE_PANES = {0: "topLeft", 1: "topRight", 2: "bottomLeft", 3: "bottomRight"} + +CELL_PROPS = ( + "CharWeight", + "CharPosture", + "CharUnderline", + "CharStrikeout", + "CharFontName", + "CharHeight", + "CharColor", + "CellBackColor", + "IsCellBackgroundTransparent", + "NumberFormat", + "HoriJustify", + "HoriJustifyMethod", + "VertJustify", + "IsTextWrapped", + "RotateAngle", + "ParaIndent", + "TopBorder2", + "BottomBorder2", + "LeftBorder2", + "RightBorder2", + "DiagonalBLTR2", + "DiagonalTLBR2", +) + + +def hmm_to_twips(value): + return int(round(value / HMM_PER_TWIP)) + + +def border_style(line): + """Map a BorderLine2 to an OOXML style (export thresholds), or None.""" + if line is None or line.LineStyle == BLS_NONE: + return None + outer = hmm_to_twips(line.OuterLineWidth or line.LineWidth) + style = line.LineStyle + if line.LineDistance > 0 or ( + style in (BLS_DOUBLE, BLS_DOUBLE_THIN) and line.InnerLineWidth > 0 + ): + return "double" + if outer >= BORDER_THICK_TWIPS: + return "thick" + if outer >= BORDER_MEDIUM_TWIPS: + return { + BLS_DASHED: "mediumDashed", + BLS_DASH_DOT: "mediumDashDot", + BLS_DASH_DOT_DOT: "mediumDashDotDot", + }.get(style, "medium") + if outer >= BORDER_THIN_TWIPS: + return { + BLS_DASHED: "dashed", + BLS_FINE_DASHED: "dashed", + BLS_DASH_DOT: "dashDot", + BLS_DASH_DOT_DOT: "dashDotDot", + BLS_DOTTED: "dotted", + }.get(style, "thin") + if outer >= BORDER_HAIR_TWIPS: + return "hair" + return None + + +def xl_rotation(rotate_angle): + """XclTools::GetXclRotation: Calc 1/100 degree -> OOXML textRotation.""" + degrees = int(rotate_angle) // 100 + if 0 <= degrees <= 90: + return degrees + if degrees < 180: + return 270 - degrees + if degrees < 270: + return degrees - 180 + if degrees < 360: + return 450 - degrees + return 0 + + +def xl_indent(para_indent_hmm): + """XclExpCellAlign: indent level = (twips + 100) / 200.""" + return (hmm_to_twips(para_indent_hmm) + 100) // 200 + + +class ModelReader: + def __init__(self, helper, doc): + self.helper = helper + self.doc = doc + self.grammar = Grammar(doc) + self.formats = doc.NumberFormats + self.format_cache = {} + null = doc.NullDate + self.null_date = datetime(null.Year, null.Month, null.Day) + self.char_width_hmm = self._default_digit_width_hmm() + self.sheet_names = list(doc.Sheets.ElementNames) + + # -------------------------------------------------------------- workbook + + def read(self): + model = { + "unsupported": {}, + "named_ranges": self.named_ranges(), + "sheets": [], + } + controller = self.doc.getCurrentController() + for index, name in enumerate(self.sheet_names): + sheet = self.doc.Sheets.getByIndex(index) + model["sheets"].append(self.read_sheet(index, name, sheet, controller)) + return model + + def _default_digit_width_hmm(self): + """Widest digit of the default font in twips, like XclRoot::SetCharWidth.""" + style = self.doc.StyleFamilies.getByName("CellStyles").getByName("Default") + descriptor = FontDescriptor() + descriptor.Name = style.CharFontName + descriptor.Height = int(round(style.CharHeight * 20)) + descriptor.Weight = style.CharWeight + font = self.doc.ReferenceDevice.getFont(descriptor) + width_twips = max(font.getCharWidth(digit) for digit in "0123456789") + if width_twips <= 0: + width_twips = 11 * descriptor.Height // 20 + return width_twips * HMM_PER_TWIP + + def named_ranges(self): + out = [] + sources = [("workbook", None, self.doc.NamedRanges)] + for name in self.sheet_names: + sources.append(("sheet", name, self.doc.Sheets.getByName(name).NamedRanges)) + for scope, sheet_name, container in sources: + for name in container.ElementNames: + named = container.getByName(name) + base = named.ReferencePosition + try: + refers_to = self.grammar.tokens_to_ooxml(named.getTokens(), base) + except Exception: + refers_to = named.Content + out.append( + { + "name": name, + "scope": scope, + "sheet": sheet_name, + "refers_to": refers_to, + } + ) + return out + + # -------------------------------------------------------------- sheet + + def read_sheet(self, index, name, sheet, controller): + cursor = sheet.createCursor() + cursor.gotoEndOfUsedArea(False) + end = cursor.RangeAddress + end_col, end_row = end.EndColumn, end.EndRow + cells = {} + for row in range(end_row + 1): + for col in range(end_col + 1): + entry = self.read_cell(sheet.getCellByPosition(col, row)) + if entry: + cells[a1(col, row)] = entry + return { + "name": name, + "cells": cells, + "row_heights": self.row_heights(sheet, end_row), + "column_widths": self.column_widths(sheet, end_col), + "merged_ranges": self.merged_ranges(sheet, end_col, end_row), + "conditional_formats": self.conditional_formats(sheet), + "data_validations": self.data_validations(sheet), + "hyperlinks": self.hyperlinks(sheet, end_col, end_row), + "images": self.images(sheet), + "pivot_tables": self.pivot_tables(sheet), + "comments": self.comments(sheet), + "freeze_panes": self.freeze_panes(sheet, name, controller), + "tables": self.tables(sheet, index), + "page_setup": self.page_setup(sheet), + "chart_anchors": self.chart_anchors(sheet), + # Last: probing for a password unprotects the in-memory sheet. + "sheet_protection": self.sheet_protection(sheet), + } + + # -------------------------------------------------------------- cells + + def number_format(self, key): + cached = self.format_cache.get(key) + if cached is None: + props = self.formats.getByKey(key) + cached = (props.FormatString, props.Type) + self.format_cache[key] = cached + return cached + + def read_cell(self, cell): + values = dict(zip(CELL_PROPS, cell.getPropertyValues(CELL_PROPS))) + format_string, format_type = self.number_format(values["NumberFormat"]) + entry = { + "format": self.cell_format(values, format_string), + "border": self.cell_border(values), + } + value = self.cell_value(cell, format_type) + if value is not None: + entry["value"] = value + return entry + + def cell_value(self, cell, format_type): + kind = cell.Type.value + if kind == "EMPTY": + return None + if kind == "TEXT": + return {"type": "string", "value": cell.String, "formula": None} + if kind == "FORMULA": + if cell.getError() != 0: + return {"type": "error", "value": cell.String, "formula": None} + formula = "=" + self.grammar.tokens_to_ooxml(cell.getTokens(), cell.CellAddress) + return {"type": "formula", "value": formula, "formula": formula} + number = cell.getValue() + if format_type & _const("com.sun.star.util.NumberFormat.LOGICAL"): + return {"type": "boolean", "value": number != 0, "formula": None} + if format_type & _const("com.sun.star.util.NumberFormat.DATE"): + stamp = self.null_date + timedelta(seconds=round(number * 86400)) + if stamp.hour == 0 and stamp.minute == 0 and stamp.second == 0: + return { + "type": "date", + "value": stamp.date().isoformat(), + "formula": None, + } + return { + "type": "datetime", + "value": stamp.isoformat(timespec="seconds"), + "formula": None, + } + return {"type": "number", "value": to_json_number(number), "formula": None} + + @staticmethod + def cell_format(values, format_string): + fmt = { + "bold": values["CharWeight"] >= 150, + "italic": values["CharPosture"].value in ("ITALIC", "OBLIQUE"), + "strikethrough": values["CharStrikeout"] not in (0, 3), + "font_name": values["CharFontName"], + "font_size": to_json_number(float(values["CharHeight"])), + "number_format": format_string, + "wrap": bool(values["IsTextWrapped"]), + } + underline = UNDERLINE_NAMES.get(values["CharUnderline"]) + if underline: + fmt["underline"] = underline + font_color = color_hex(values["CharColor"]) + if font_color: + fmt["font_color"] = font_color + if not values["IsCellBackgroundTransparent"]: + bg = color_hex(values["CellBackColor"]) + if bg: + fmt["bg_color"] = bg + h_align = H_ALIGN_NAMES.get(values["HoriJustify"].value) + if h_align == "justify" and values["HoriJustifyMethod"] == 1: + h_align = "distributed" + if h_align: + fmt["h_align"] = h_align + v_align = V_ALIGN_NAMES.get(values["VertJustify"]) + if v_align: + fmt["v_align"] = v_align + rotation = xl_rotation(values["RotateAngle"]) + if rotation: + fmt["rotation"] = rotation + indent = xl_indent(values["ParaIndent"]) + if indent: + fmt["indent"] = indent + return fmt + + @staticmethod + def cell_border(values): + border = {} + for edge, prop in ( + ("top", "TopBorder2"), + ("bottom", "BottomBorder2"), + ("left", "LeftBorder2"), + ("right", "RightBorder2"), + ("diagonal_up", "DiagonalBLTR2"), + ("diagonal_down", "DiagonalTLBR2"), + ): + line = values[prop] + style = border_style(line) + if style: + border[edge] = { + "style": style, + "color": color_hex(line.Color) or "#000000", + } + return border + + # -------------------------------------------------------------- dimensions + + @staticmethod + def row_heights(sheet, end_row): + out = {} + rows = sheet.Rows + for row in range(max(end_row + 1, MIN_SCAN_ROWS)): + props = rows.getByIndex(row) + if props.OptimalHeight: + continue + twips = hmm_to_twips(props.Height) + out[str(row + 1)] = to_json_number(twips / 20.0) + return out + + def column_widths(self, sheet, end_col): + out = {} + columns = sheet.Columns + for col in range(max(end_col + 1, MIN_SCAN_COLS)): + width = columns.getByIndex(col).Width + chars = int(width / self.char_width_hmm * 100.0 + 0.5) / 100.0 + out[col_letter(col)] = chars + return out + + # -------------------------------------------------------------- merges + + @staticmethod + def merged_ranges(sheet, end_col, end_row): + out = [] + for row in range(end_row + 1): + for col in range(end_col + 1): + single = sheet.getCellRangeByPosition(col, row, col, row) + if not single.getIsMerged(): + continue + cursor = sheet.createCursorByRange(single) + cursor.collapseToMergedArea() + rng = a1_range(cursor.RangeAddress) + if ":" in rng and rng not in out: + out.append(rng) + return out + + # -------------------------------------------------------------- CF / DV + + def _ranges_string(self, addresses): + return " ".join(a1_range(addr) for addr in addresses) + + def conditional_formats(self, sheet): + out = [] + styles = self.doc.StyleFamilies.getByName("CellStyles") + for cond_format in sheet.ConditionalFormats.ConditionalFormats: + addresses = cond_format.Range.RangeAddresses + if not addresses: + continue + range_text = self._ranges_string(addresses) + first = addresses[0] + base = CellAddress(first.Sheet, first.StartColumn, first.StartRow) + for position in range(cond_format.Count): + entry = cond_format.getByIndex(position) + info = entry.getPropertySetInfo() + rule = { + "range": range_text, + "rule_type": None, + "operator": None, + "formula": None, + "priority": None, + "stop_if_true": None, + "format": {}, + } + # The numeric getType() codes differ between entry + # implementations, so classify by the properties each kind + # of entry object exposes. + if info.hasPropertyByName("ColorScaleEntries"): + rule["rule_type"] = "colorScale" + elif info.hasPropertyByName("DataBarEntries"): + rule["rule_type"] = "dataBar" + elif info.hasPropertyByName("IconSetEntries"): + rule["rule_type"] = "iconSet" + elif info.hasPropertyByName("DateType"): + rule["rule_type"] = "timePeriod" + rule["format"] = self._style_colors(styles, entry.StyleName) + elif info.hasPropertyByName("Operator"): + rule_type, operator = CF_OPERATORS.get(entry.Operator, (None, None)) + rule["rule_type"] = rule_type + rule["operator"] = operator + formula = entry.Formula1 + if formula: + try: + rule["formula"] = self.grammar.calc_to_ooxml(formula, base, native=True) + except Exception: + rule["formula"] = formula + rule["format"] = self._style_colors(styles, entry.StyleName) + out.append(rule) + return out + + @staticmethod + def _style_colors(styles, style_name): + if not style_name or not styles.hasByName(style_name): + return {} + style = styles.getByName(style_name) + out = {} + if not style.IsCellBackgroundTransparent: + bg = color_hex(style.CellBackColor) + if bg: + out["bg_color"] = bg + direct = uno.Enum("com.sun.star.beans.PropertyState", "DIRECT_VALUE") + if style.getPropertyState("CharColor") == direct: + font_color = color_hex(style.CharColor) + if font_color: + out["font_color"] = font_color + return out + + def data_validations(self, sheet): + groups = {} + order = [] + unique = sheet.UniqueCellFormatRanges + for index in range(unique.Count): + ranges = unique.getByIndex(index) + validation = ranges.Validation + if validation.Type.value == "ANY": + continue + addresses = ranges.RangeAddresses + first = addresses[0] + base = CellAddress(first.Sheet, first.StartColumn, first.StartRow) + record = self._validation_record(validation, base) + key = json.dumps(record, sort_keys=True) + if key not in groups: + groups[key] = (record, []) + order.append(key) + groups[key][1].extend(addresses) + out = [] + for key in order: + record, addresses = groups[key] + container = self.doc.createInstance("com.sun.star.sheet.SheetCellRanges") + container.addRangeAddresses(tuple(addresses), True) + merged = sorted(container.RangeAddresses, key=lambda a: (a.StartRow, a.StartColumn)) + out.append({"range": self._ranges_string(merged), **record}) + return out + + def _validation_record(self, validation, base): + dv_type = DV_TYPES.get(validation.Type.value, validation.Type.value.lower()) + formula1 = self._validation_formula(validation.getFormula1(), base, dv_type == "list") + formula2 = None + operator = CONDITION_OPERATORS.get(validation.Operator.value) + if operator in ("between", "notBetween"): + formula2 = self._validation_formula(validation.getFormula2(), base, False) + return { + "validation_type": dv_type, + "operator": operator, + "formula1": formula1, + "formula2": formula2, + "allow_blank": bool(validation.IgnoreBlankCells), + "show_input": bool(validation.ShowInputMessage), + "show_error": bool(validation.ShowErrorMessage), + "prompt_title": validation.InputTitle or None, + "prompt": validation.InputMessage or None, + "error_title": validation.ErrorTitle or None, + "error": validation.ErrorMessage or None, + } + + def _validation_formula(self, text, base, is_list): + """Print a validation formula (Calc API grammar) in OOXML grammar.""" + if not text: + return None + tokens = self.grammar.api.parseFormula(text, base) + if is_list: + # A list of string constants is written by Calc's xlsx export as one + # quoted comma-joined literal (XclExpDV); report it the same way. + strings = [] + only_strings = True + for index, token in enumerate(tokens): + if index % 2 == 0: + if token.OpCode == 0 and isinstance(token.Data, str): + strings.append(token.Data) + else: + only_strings = False + break + if only_strings and strings and len(tokens) == 2 * len(strings) - 1: + return '"' + ",".join(strings) + '"' + return self.grammar.tokens_to_ooxml(tokens, base) + + # -------------------------------------------------------------- links + + def hyperlinks(self, sheet, end_col, end_row): + out = [] + for row in range(end_row + 1): + for col in range(end_col + 1): + cell = sheet.getCellByPosition(col, row) + if cell.Type.value == "EMPTY": + continue + found = False + fields = cell.Text.TextFields.createEnumeration() + while fields.hasMoreElements(): + field = fields.nextElement() + if not field.getPropertySetInfo().hasPropertyByName("URL"): + continue + found = True + out.append(self._link_record(sheet, a1(col, row), cell, field.URL)) + cell_link = cell.Hyperlink + if cell_link and not found: + out.append(self._link_record(sheet, a1(col, row), cell, cell_link)) + return out + + def _link_record(self, sheet, ref, cell, url): + internal = url.startswith("#") + target = url + if internal: + # Calc stores internal targets in its own grammar ("Sheet.A1"); + # print them in OOXML grammar. A target Calc cannot parse as a + # reference (e.g. a defined name) is reported verbatim. + location = url[1:] + base = CellAddress(sheet.RangeAddress.Sheet, 0, 0) + try: + target = self.grammar.calc_to_ooxml(location, base) + except Exception: + target = location + return { + "cell": ref, + "target": target, + "display": cell.String, + "tooltip": None, + "internal": internal, + } + + # -------------------------------------------------------------- drawings + + @staticmethod + def _anchor(shape): + anchor = shape.Anchor + address = getattr(anchor, "CellAddress", None) if anchor is not None else None + if address is None: + return None, None + kind = "twoCell" if shape.ResizeWithCell else "oneCell" + return address, kind + + @staticmethod + def _cell_at(sheet, x, y): + """Cell holding the shape end point (x, y) in 1/100 mm. + + Uses Calc's own cell positions (accumulated in twips, so they differ + from summing the rounded 1/100 mm sizes). A point exactly on a cell + boundary belongs to the preceding cell with a full-size offset, the + convention Calc's xlsx export uses for the ``xdr:to`` anchor. + """ + last_col = sheet.Columns.Count - 1 + last_row = sheet.Rows.Count - 1 + col = 0 + while col < last_col and sheet.getCellByPosition(col + 1, 0).Position.X < x: + col += 1 + row = 0 + while row < last_row and sheet.getCellByPosition(0, row + 1).Position.Y < y: + row += 1 + return col, row + + def images(self, sheet): + out = [] + page = sheet.DrawPage + for index in range(page.Count): + shape = page.getByIndex(index) + if shape.ShapeType != "com.sun.star.drawing.GraphicObjectShape": + continue + address, kind = self._anchor(shape) + offset = None + if address is not None: + cell = sheet.getCellByPosition(address.Column, address.Row) + origin = cell.Position + offset = [ + (shape.Position.X - origin.X) * EMU_PER_HMM, + (shape.Position.Y - origin.Y) * EMU_PER_HMM, + ] + out.append( + { + "cell": a1(address.Column, address.Row) if address is not None else None, + "path": None, + "anchor": kind, + "offset": offset, + "alt_text": shape.Description or None, + } + ) + return out + + def chart_anchors(self, sheet): + out = [] + shapes = {} + page = sheet.DrawPage + for index in range(page.Count): + shape = page.getByIndex(index) + if shape.ShapeType == "com.sun.star.drawing.OLE2Shape": + shapes[shape.PersistName] = shape + charts = sheet.Charts + for name in charts.ElementNames: + chart = charts.getByName(name) + shape = shapes.get(name) + chart_type = None + embedded = chart.EmbeddedObject + if embedded is not None: + diagram = embedded.getFirstDiagram() + if diagram is not None: + for system in diagram.getCoordinateSystems(): + for kind in system.getChartTypes(): + chart_type = CHART_TYPES.get(kind.ChartType, kind.ChartType) + break + if chart_type: + break + record = {"type": chart_type, "anchor_type": None, "from": None, "to": None} + if shape is not None: + address, kind = self._anchor(shape) + record["anchor_type"] = kind + if address is not None: + record["from"] = a1(address.Column, address.Row) + if kind == "twoCell": + col, row = self._cell_at( + sheet, + shape.Position.X + shape.Size.Width, + shape.Position.Y + shape.Size.Height, + ) + record["to"] = a1(col, row) + out.append(record) + return out + + # -------------------------------------------------------------- objects + + def pivot_tables(self, sheet): + out = [] + pivots = sheet.DataPilotTables + for name in pivots.ElementNames: + pivot = pivots.getByName(name) + source = pivot.SourceRange + output = pivot.OutputRange + out.append( + { + "name": name, + "source_range": f"{self.sheet_names[source.Sheet]}!{a1_range(source)}", + "target_cell": f"{self.sheet_names[output.Sheet]}!" + f"{a1(output.StartColumn, output.StartRow)}", + } + ) + return out + + @staticmethod + def comments(sheet): + out = [] + for annotation in sheet.Annotations: + position = annotation.Position + shape = annotation.AnnotationShape + text = shape.String if shape is not None else annotation.String + out.append( + { + "cell": a1(position.Column, position.Row), + "text": text, + "author": annotation.Author or None, + "threaded": False, + } + ) + return out + + def freeze_panes(self, sheet, name, controller): + if controller is not None: + controller.setActiveSheet(sheet) + if controller.hasFrozenPanes(): + return { + "mode": "freeze", + "top_left_cell": a1(controller.getSplitColumn(), controller.getSplitRow()), + } + settings = self._view_settings(name) + if not settings: + return {} + h_mode = settings.get("HorizontalSplitMode", 0) + v_mode = settings.get("VerticalSplitMode", 0) + if h_mode != 1 and v_mode != 1: + return {} + out = { + "mode": "split", + "x_split": int(settings.get("HorizontalSplitPositionTwips", 0)) if h_mode == 1 else 0, + "y_split": int(settings.get("VerticalSplitPositionTwips", 0)) if v_mode == 1 else 0, + "top_left_cell": a1( + int(settings.get("PositionRight", 0)), + int(settings.get("PositionBottom", 0)), + ), + } + pane = ACTIVE_PANES.get(settings.get("ActiveSplitRange")) + if pane: + out["active_pane"] = pane + return out + + def _view_settings(self, sheet_name): + view_data = self.doc.ViewData + if view_data is None or view_data.Count == 0: + return {} + view = {prop.Name: prop.Value for prop in view_data.getByIndex(0)} + tables = view.get("Tables") + if tables is None or not tables.hasByName(sheet_name): + return {} + return {prop.Name: prop.Value for prop in tables.getByName(sheet_name)} + + def tables(self, sheet, index): + out = [] + ranges = self.doc.DatabaseRanges + for name in ranges.ElementNames: + db_range = ranges.getByName(name) + area = db_range.DataArea + if area.Sheet != index: + continue + header = bool(db_range.ContainsHeader) + columns = [] + if header: + for col in range(area.StartColumn, area.EndColumn + 1): + columns.append(sheet.getCellByPosition(col, area.StartRow).String) + style = getattr(db_range, "TableStyleName", None) + out.append( + { + "name": name, + "ref": a1_range(area), + "header_row": header, + "totals_row": bool(getattr(db_range, "TotalsRow", False)), + "style": style if style and style != "none" else None, + "columns": columns, + "autofilter": bool(db_range.AutoFilter), + } + ) + return out + + @staticmethod + def sheet_protection(sheet): + protected = bool(sheet.isProtected()) + password = False + if protected: + # XProtectable has no "has password" query: an empty password + # unprotects only a sheet that has none. + try: + sheet.unprotect("") + except Exception: + password = True + return { + "protected": protected, + "password_hash_present": password, + "format_cells": None, + "insert_rows": None, + "select_locked_cells": None, + "select_unlocked_cells": None, + "sort": None, + "auto_filter": None, + } + + def page_setup(self, sheet): + style = self.doc.StyleFamilies.getByName("PageStyles").getByName(sheet.PageStyle) + out = { + "orientation": "landscape" if style.IsLandscape else "portrait", + "fit_to_width": None, + "fit_to_height": None, + "scale": None, + "print_title_rows": None, + "header_center": None, + "footer_center": None, + } + if style.ScaleToPagesX or style.ScaleToPagesY: + out["fit_to_width"] = int(style.ScaleToPagesX) or None + out["fit_to_height"] = int(style.ScaleToPagesY) or None + elif not style.ScaleToPages: + out["scale"] = int(style.PageScale) + if sheet.getPrintTitleRows(): + rows = sheet.getTitleRows() + out["print_title_rows"] = f"${rows.StartRow + 1}:${rows.EndRow + 1}" + if style.HeaderIsOn: + out["header_center"] = header_footer_text(style.RightPageHeaderContent.CenterText) + if style.FooterIsOn: + out["footer_center"] = header_footer_text(style.RightPageFooterContent.CenterText) + return out + + +# Text field service -> OOXML header/footer code (XclExpHFConverter). +HF_FIELD_CODES = ( + ("PageNumber", "&P"), + ("PageCount", "&N"), + ("PageCountRange", "&N"), + ("DateTime", "&D"), + ("Date", "&D"), + ("Time", "&T"), + ("SheetName", "&A"), + ("FileName", "&F"), +) + + +def header_footer_text(text): + parts = [] + paragraphs = text.createEnumeration() + first = True + while paragraphs.hasMoreElements(): + paragraph = paragraphs.nextElement() + if not first: + parts.append("\n") + first = False + portions = paragraph.createEnumeration() + while portions.hasMoreElements(): + portion = portions.nextElement() + if portion.TextPortionType == "TextField": + field = portion.TextField + code = None + for service, mapped in HF_FIELD_CODES: + if field.supportsService( + f"com.sun.star.text.TextField.{service}" + ) or field.supportsService(f"com.sun.star.text.textfield.{service}"): + code = mapped + break + parts.append(code if code is not None else portion.String) + else: + parts.append(portion.String.replace("&", "&&")) + value = "".join(parts) + return value or None + + +# ============================================================================= +# Write side +# ============================================================================= + +H_ALIGN_VALUES = { + "general": "STANDARD", + "left": "LEFT", + "center": "CENTER", + "right": "RIGHT", + "justify": "BLOCK", + "distributed": "BLOCK", + "fill": "REPEAT", +} +V_ALIGN_VALUES = {"top": 1, "center": 2, "bottom": 3, "justify": 4, "distributed": 4} + +# OOXML border style -> (BorderLineStyle, width in 1/100 mm). Widths are the +# ones LibreOffice's own OOXML import assigns (thin 15, medium 35, thick 50 +# twips); the export maps them back through lclGetBorderLine. +BORDER_WRITE = { + "thin": (BLS_SOLID, 26), + "medium": (BLS_SOLID, 62), + "thick": (BLS_SOLID, 88), + "double": (BLS_DOUBLE_THIN, 62), + "hair": (BLS_SOLID, 2), + "dotted": (BLS_DOTTED, 26), + "dashed": (BLS_FINE_DASHED, 26), + "dashDot": (BLS_DASH_DOT, 26), + "dashDotDot": (BLS_DASH_DOT_DOT, 26), + "mediumDashed": (BLS_DASHED, 62), + "mediumDashDot": (BLS_DASH_DOT, 62), + "mediumDashDotDot": (BLS_DASH_DOT_DOT, 62), + "slantDashDot": (BLS_DASH_DOT, 62), +} +BORDER_PROPS = { + "top": "TopBorder2", + "bottom": "BottomBorder2", + "left": "LeftBorder2", + "right": "RightBorder2", + "diagonal_up": "DiagonalBLTR2", + "diagonal_down": "DiagonalTLBR2", +} +UNDERLINE_VALUES = {name: value for value, name in UNDERLINE_NAMES.items()} +UNDERLINE_VALUES.update({"singleAccounting": 1, "doubleAccounting": 2, "none": 0}) + +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", +} + +CF_OPERATOR_VALUES = { + "equal": 0, + "lessThan": 1, + "greaterThan": 2, + "lessThanOrEqual": 3, + "greaterThanOrEqual": 4, + "notEqual": 5, + "between": 6, + "notBetween": 7, +} +DV_TYPE_VALUES = { + "whole": "WHOLE", + "decimal": "DECIMAL", + "date": "DATE", + "time": "TIME", + "textLength": "TEXT_LEN", + "list": "LIST", + "custom": "CUSTOM", + "any": "ANY", + "none": "ANY", +} +CONDITION_OPERATOR_VALUES = {v: k for k, v in CONDITION_OPERATORS.items()} + +HF_CODE_SERVICES = { + "P": "com.sun.star.text.TextField.PageNumber", + "N": "com.sun.star.text.TextField.PageCount", + "D": "com.sun.star.text.TextField.Date", + "T": "com.sun.star.text.TextField.Time", + "A": "com.sun.star.text.TextField.SheetName", + "F": "com.sun.star.text.TextField.FileName", +} + + +class BarEntry(unohelper.Base, XDataBarEntry): + def __init__(self, entry_type, formula): + self._type = entry_type + self._formula = formula + + def getType(self): + return self._type + + def setType(self, value): + self._type = value + + def getFormula(self): + return self._formula + + def setFormula(self, value): + self._formula = value + + +class OpWriter: + def __init__(self, helper, doc): + self.helper = helper + self.doc = doc + self.grammar = Grammar(doc) + self.default_sheets = list(doc.Sheets.ElementNames) + self.requested = [] + self.sheets_final = False + # Empty locale = the document's default language, which is what Calc's + # UI uses; an explicit locale makes the xlsx export prefix "[$-409]". + self.locale = Locale() + self.char_width_hmm = None + self.style_counter = 0 + + def apply(self, ops): + for op in ops: + kind = op.get("op") + if kind == "add_sheet": + self.add_sheet(str(op["name"])) + continue + self.finalize_sheets() + handler = getattr(self, f"op_{kind}", None) + if handler is None: + raise ValueError(f"unknown write op {kind!r}") + handler(op) + self.finalize_sheets() + + # -------------------------------------------------------------- sheets + + def add_sheet(self, name): + if self.sheets_final: + raise ValueError("add_sheet after other ops is not part of the contract") + sheets = self.doc.Sheets + position = len(self.requested) + if sheets.hasByName(name): + sheets.moveByName(name, position) + else: + sheets.insertNewByName(name, position) + self.requested.append(name) + + def finalize_sheets(self): + if self.sheets_final: + return + self.sheets_final = True + if not self.requested: + return + for name in self.default_sheets: + if name not in self.requested and self.doc.Sheets.hasByName(name): + self.doc.Sheets.removeByName(name) + + def sheet(self, name): + if not self.doc.Sheets.hasByName(name): + raise KeyError(f"sheet not found: {name}") + return self.doc.Sheets.getByName(name) + + def cell(self, op, ref=None): + sheet = self.sheet(op["sheet"]) + col, row = parse_a1(ref or op["cell"]) + return sheet.getCellByPosition(col, row) + + def sheet_index(self, name): + return list(self.doc.Sheets.ElementNames).index(name) + + # -------------------------------------------------------------- cells + + def op_cell_value(self, op): + cell = self.cell(op) + kind = op.get("type") + value = op.get("value") + if kind == "blank" or (kind == "string" and value is None): + cell.setString("") + elif kind == "string": + cell.setString(str(value)) + elif kind == "number": + cell.setValue(float(value)) + elif kind == "boolean": + cell.setValue(1.0 if value else 0.0) + cell.NumberFormat = standard_format(self.doc, "LOGICAL") + elif kind in ("date", "datetime"): + stamp = datetime.fromisoformat(str(value)) + null = self.doc.NullDate + delta = stamp - datetime(null.Year, null.Month, null.Day) + cell.setValue(delta.days + delta.seconds / 86400.0) + cell.NumberFormat = standard_format(self.doc, "DATE" if kind == "date" else "DATETIME") + elif kind == "formula": + self.set_formula(cell, op.get("formula") or value) + elif kind == "error": + formula = ERROR_FORMULAS.get(str(value)) + if formula is None: + raise ValueError(f"no formula produces error {value!r}") + self.set_formula(cell, formula) + else: + raise ValueError(f"unknown cell value type {kind!r}") + + def set_formula(self, cell, text): + tokens = self.grammar.ooxml_to_tokens(strip_eq(text), cell.CellAddress) + cell.setTokens(tokens) + + def number_format_key(self, code): + formats = self.doc.NumberFormats + key = formats.queryKey(code, self.locale, False) + if key == -1: + key = formats.addNew(code, self.locale) + return key + + def op_cell_format(self, op): + cell = self.cell(op) + fmt = op.get("format") or {} + if fmt.get("bold") is not None: + cell.CharWeight = 150.0 if fmt["bold"] else 100.0 + if fmt.get("italic") is not None: + cell.CharPosture = _enum( + "com.sun.star.awt.FontSlant", "ITALIC" if fmt["italic"] else "NONE" + ) + if fmt.get("underline") is not None: + name = str(fmt["underline"]) + if name not in UNDERLINE_VALUES: + raise ValueError(f"LibreOffice has no underline kind {name!r}") + cell.CharUnderline = UNDERLINE_VALUES[name] + if fmt.get("strikethrough") is not None: + cell.CharStrikeout = 1 if fmt["strikethrough"] else 0 + if fmt.get("font_name") is not None: + cell.CharFontName = str(fmt["font_name"]) + if fmt.get("font_size") is not None: + cell.CharHeight = float(fmt["font_size"]) + if fmt.get("font_color") is not None: + cell.CharColor = color_int(fmt["font_color"]) + if fmt.get("bg_color") is not None: + cell.CellBackColor = color_int(fmt["bg_color"]) + cell.IsCellBackgroundTransparent = False + if fmt.get("number_format") is not None: + cell.NumberFormat = self.number_format_key(str(fmt["number_format"])) + if fmt.get("h_align") is not None: + value = H_ALIGN_VALUES.get(str(fmt["h_align"])) + if value is None: + raise ValueError(f"LibreOffice has no horizontal alignment {fmt['h_align']!r}") + cell.HoriJustify = _enum("com.sun.star.table.CellHoriJustify", value) + if fmt["h_align"] == "distributed": + cell.HoriJustifyMethod = 1 + if fmt.get("v_align") is not None: + value = V_ALIGN_VALUES.get(str(fmt["v_align"])) + if value is None: + raise ValueError(f"LibreOffice has no vertical alignment {fmt['v_align']!r}") + cell.VertJustify = value + if fmt["v_align"] == "distributed": + cell.VertJustifyMethod = 1 + if fmt.get("wrap") is not None: + cell.IsTextWrapped = bool(fmt["wrap"]) + if fmt.get("rotation") is not None: + rotation = int(fmt["rotation"]) + if rotation == 255: + cell.Orientation = _enum("com.sun.star.table.CellOrientation", "STACKED") + elif rotation <= 90: + cell.RotateAngle = rotation * 100 + else: + cell.RotateAngle = (360 - (rotation - 90)) * 100 + if fmt.get("indent") is not None: + # Inverse of the export's (twips + 100) / 200 indent level. + cell.ParaIndent = int(round(int(fmt["indent"]) * 200 * HMM_PER_TWIP)) + + def op_cell_border(self, op): + cell = self.cell(op) + for edge, spec in (op.get("border") or {}).items(): + prop = BORDER_PROPS.get(edge) + if prop is None: + raise ValueError(f"unknown border edge {edge!r}") + style = str(spec.get("style") or "thin") + if style not in BORDER_WRITE: + raise ValueError(f"LibreOffice has no border style {style!r}") + line_style, width = BORDER_WRITE[style] + line = BorderLine2() + line.LineStyle = line_style + line.LineWidth = width + line.Color = color_int(spec.get("color") or "#000000") + cell.setPropertyValue(prop, line) + + # -------------------------------------------------------------- dimensions + + def op_row_height(self, op): + sheet = self.sheet(op["sheet"]) + row = sheet.Rows.getByIndex(int(op["row"]) - 1) + row.Height = int(round(float(op["height"]) * 20 * HMM_PER_TWIP)) + + def op_column_width(self, op): + sheet = self.sheet(op["sheet"]) + col, _ = parse_a1(f"{op['column']}1") + if self.char_width_hmm is None: + self.char_width_hmm = ModelReader._default_digit_width_hmm(self) + column = sheet.Columns.getByIndex(col) + column.Width = int(round(float(op["width"]) * self.char_width_hmm)) + + def op_merge(self, op): + self.sheet(op["sheet"]).getCellRangeByName(op["range"]).merge(True) + + # -------------------------------------------------------------- CF / DV + + def cell_ranges(self, sheet, text): + container = self.doc.createInstance("com.sun.star.sheet.SheetCellRanges") + for part in str(text).replace(",", " ").split(): + container.addRangeAddress( + sheet.getCellRangeByName(part.replace("$", "")).RangeAddress, False + ) + return container + + def style_for(self, fmt): + self.style_counter += 1 + name = f"ExcelBench_CF_{self.style_counter}" + style = self.doc.createInstance("com.sun.star.style.CellStyle") + self.doc.StyleFamilies.getByName("CellStyles").insertByName(name, style) + if fmt.get("bg_color"): + style.CellBackColor = color_int(fmt["bg_color"]) + style.IsCellBackgroundTransparent = False + if fmt.get("font_color"): + style.CharColor = color_int(fmt["font_color"]) + return name + + def op_conditional_format(self, op): + sheet = self.sheet(op["sheet"]) + rule = op.get("rule") or {} + rule_type = rule.get("rule_type") + if rule_type == "colorScale": + # Not written. A color scale created through createEntry(COLORSCALE) + # has zero scale entries, and setting ColorScaleEntries indexes the + # existing entries without growing them (ScColorScaleFormatObj), which + # aborts soffice (SIGABRT). No other UNO call adds scale entries, so + # the rule is left out and its test case fails. + return + ranges = self.cell_ranges(sheet, rule["range"]) + first = ranges.RangeAddresses[0] + base = CellAddress(first.Sheet, first.StartColumn, first.StartRow) + formats = sheet.ConditionalFormats + format_id = formats.createByRange(ranges) + target = next(f for f in formats.ConditionalFormats if f.ID == format_id) + entry_types = "com.sun.star.sheet.ConditionEntryType." + if rule_type in ("cellIs", "cellIsRule", "expression", "formula"): + target.createEntry(_const(entry_types + "CONDITION"), target.Count) + entry = target.getByIndex(target.Count - 1) + if rule_type in ("cellIs", "cellIsRule"): + operator = CF_OPERATOR_VALUES.get(rule.get("operator")) + if operator is None: + raise ValueError(f"unknown cellIs operator {rule.get('operator')!r}") + else: + operator = 24 + entry.Operator = operator + formula = rule.get("formula") + if formula: + entry.Formula1 = self.grammar.ooxml_to_calc(strip_eq(formula), base, native=True) + entry.StyleName = self.style_for(rule.get("format") or {}) + elif rule_type == "dataBar": + target.createEntry(_const(entry_types + "DATABAR"), target.Count) + entry = target.getByIndex(target.Count - 1) + kind = "com.sun.star.sheet.DataBarEntryType." + entry.DataBarEntries = ( + BarEntry(_const(kind + "DATABAR_MIN"), ""), + BarEntry(_const(kind + "DATABAR_MAX"), ""), + ) + entry.Color = 0x638EC6 + entry.ShowValue = True + else: + raise ValueError(f"unsupported conditional format rule_type {rule_type!r}") + # stop_if_true and priority: Calc's conditional-format API has no such + # properties; entries are evaluated in insertion order. + + def op_data_validation(self, op): + sheet = self.sheet(op["sheet"]) + spec = op.get("validation") or {} + ranges = self.cell_ranges(sheet, spec["range"]) + first = ranges.RangeAddresses[0] + base = CellAddress(first.Sheet, first.StartColumn, first.StartRow) + dv_type = DV_TYPE_VALUES.get(str(spec.get("validation_type") or "any")) + if dv_type is None: + raise ValueError(f"unknown validation type {spec.get('validation_type')!r}") + for address in ranges.RangeAddresses: + target = sheet.getCellRangeByPosition( + address.StartColumn, address.StartRow, address.EndColumn, address.EndRow + ) + validation = target.Validation + validation.Type = _enum("com.sun.star.sheet.ValidationType", dv_type) + operator = spec.get("operator") + if operator is None and spec.get("formula2") is not None: + operator = "between" + if dv_type == "CUSTOM": + validation.Operator = _enum("com.sun.star.sheet.ConditionOperator", "FORMULA") + elif operator is not None: + value = CONDITION_OPERATOR_VALUES.get(str(operator)) + if value is None: + raise ValueError(f"unknown validation operator {operator!r}") + validation.Operator = _enum("com.sun.star.sheet.ConditionOperator", value) + elif dv_type == "LIST": + validation.Operator = _enum("com.sun.star.sheet.ConditionOperator", "EQUAL") + # Relative references are anchored at the top-left cell of the first + # range (OOXML semantics); Calc anchors them at SourcePosition. + validation.setSourcePosition(base) + for position, key in ((0, "formula1"), (1, "formula2")): + text = spec.get(key) + if text is None: + continue + validation.setTokens(position, self.validation_tokens(str(text), base, dv_type)) + if spec.get("allow_blank") is not None: + validation.IgnoreBlankCells = bool(spec["allow_blank"]) + if spec.get("show_input") is not None: + validation.ShowInputMessage = bool(spec["show_input"]) + if spec.get("show_error") is not None: + validation.ShowErrorMessage = bool(spec["show_error"]) + for key, prop in ( + ("prompt_title", "InputTitle"), + ("prompt", "InputMessage"), + ("error_title", "ErrorTitle"), + ("error", "ErrorMessage"), + ): + if spec.get(key) is not None: + validation.setPropertyValue(prop, str(spec[key])) + target.Validation = validation + + def validation_tokens(self, text, base, dv_type): + text = strip_eq(text) + if ( + dv_type == "LIST" + and len(text) >= 2 + and text[0] == '"' + and text[-1] == '"' + and '"' not in text[1:-1] + ): + # OOXML stores an explicit list as one quoted comma-joined literal; + # Calc models it as separate string constants (what its import builds). + items = text[1:-1].split(",") + calc = ";".join('"' + item + '"' for item in items) + return self.grammar.api.parseFormula(calc, base) + return self.grammar.ooxml_to_tokens(text, base) + + # -------------------------------------------------------------- links etc. + + def op_hyperlink(self, op): + link = op.get("link") or {} + cell = self.cell(op, link["cell"]) + target = str(link.get("target") or "") + if link.get("internal"): + # Calc keeps internal targets as "#Sheet.A1"; translate an OOXML + # "Sheet!A1" location when it names an existing sheet. Anything else + # (unknown sheet, defined name) is stored verbatim as the fragment. + location = target.lstrip("#") + sheet_part = location.rsplit("!", 1)[0].strip("'") if "!" in location else None + if sheet_part is not None and self.doc.Sheets.hasByName(sheet_part): + base = CellAddress(self.sheet_index(op["sheet"]), 0, 0) + url = "#" + self.grammar.ooxml_to_calc(location, base) + else: + url = "#" + location + else: + url = target + display = link.get("display") + if display is None: + display = cell.String or target + cell.setString("") + text = cell.Text + field = self.doc.createInstance("com.sun.star.text.TextField.URL") + field.URL = url + field.Representation = str(display) + text.insertTextContent(text.createTextCursor(), field, False) + # tooltip: the Calc URL text field has no ScreenTip property. + + def op_image(self, op): + spec = op.get("image") or {} + sheet = self.sheet(op["sheet"]) + path = spec.get("path") + if not path or not os.path.isfile(path): + raise ValueError(f"image path does not exist: {path!r}") + provider = self.helper.create("com.sun.star.graphic.GraphicProvider") + graphic = provider.queryGraphic((pv("URL", uno.systemPathToFileUrl(path)),)) + shape = self.doc.createInstance("com.sun.star.drawing.GraphicObjectShape") + sheet.DrawPage.add(shape) + shape.Graphic = graphic + size = graphic.Size100thMM + if size.Width <= 0 or size.Height <= 0: + pixels = graphic.SizePixel + size = Size(int(pixels.Width * 2540 / 96), int(pixels.Height * 2540 / 96)) + shape.Size = size + col, row = parse_a1(spec["cell"]) + cell = sheet.getCellByPosition(col, row) + shape.Position = cell.Position + shape.Anchor = cell + shape.ResizeWithCell = spec.get("anchor") == "twoCell" + + def op_comment(self, op): + spec = op.get("comment") or {} + sheet = self.sheet(op["sheet"]) + col, row = parse_a1(spec["cell"]) + sheet.Annotations.insertNew( + CellAddress(self.sheet_index(op["sheet"]), col, row), + str(spec.get("text") or ""), + ) + # author: XSheetAnnotation exposes Author read-only; new notes carry the + # profile's user name. + + def op_freeze(self, op): + settings = op.get("settings") or {} + sheet = self.sheet(op["sheet"]) + mode = settings.get("mode") + controller = self.doc.getCurrentController() + if mode == "freeze": + col, row = parse_a1(settings.get("top_left_cell") or "A1") + controller.setActiveSheet(sheet) + controller.freezeAtPosition(col, row) + elif mode == "split": + # OOXML split offsets are twips; XViewSplitable takes pixels at the + # view zoom (100% => 1440 twips per 96 px). + x_pixels = round(int(settings.get("x_split") or 0) * 96 / 1440) + y_pixels = round(int(settings.get("y_split") or 0) * 96 / 1440) + controller.setActiveSheet(sheet) + controller.splitAtPosition(x_pixels, y_pixels) + else: + raise ValueError(f"unknown freeze mode {mode!r}") + + def op_named_range(self, op): + spec = op.get("named_range") or {} + scope = spec.get("scope") or "workbook" + container = ( + self.sheet(op["sheet"]).NamedRanges if scope == "sheet" else self.doc.NamedRanges + ) + base = CellAddress(self.sheet_index(op["sheet"]), 0, 0) + content = self.grammar.ooxml_to_calc(strip_eq(spec["refers_to"]), base) + container.addNewByName(str(spec["name"]), content, base, 0) + + def op_table(self, op): + spec = op.get("table") or {} + sheet = self.sheet(op["sheet"]) + area = sheet.getCellRangeByName(spec["ref"]).RangeAddress + ranges = self.doc.DatabaseRanges + ranges.addNewByName(str(spec["name"]), area) + db_range = ranges.getByName(str(spec["name"])) + db_range.ContainsHeader = spec.get("header_row") is not False + if spec.get("totals_row") is not None: + db_range.TotalsRow = bool(spec["totals_row"]) + if spec.get("style"): + db_range.TableStyleName = str(spec["style"]) + db_range.UseRowStripes = True + if spec.get("autofilter"): + db_range.AutoFilter = True + + def op_protection(self, op): + settings = op.get("settings") or {} + sheet = self.sheet(op["sheet"]) + if settings.get("protected") is False: + if sheet.isProtected(): + sheet.unprotect(str(settings.get("password") or "")) + return + sheet.protect(str(settings.get("password") or "")) + # The granular flags (format_cells, insert_rows, select_*, sort, + # auto_filter) have no UNO API: XProtectable only takes a password. + + def page_style(self, sheet_name): + sheet = self.sheet(sheet_name) + styles = self.doc.StyleFamilies.getByName("PageStyles") + name = f"ExcelBench_{sheet_name}" + if not styles.hasByName(name): + styles.insertByName(name, self.doc.createInstance("com.sun.star.style.PageStyle")) + sheet.PageStyle = name + return sheet, styles.getByName(name) + + def op_page_setup(self, op): + settings = op.get("settings") or {} + sheet, style = self.page_style(op["sheet"]) + orientation = settings.get("orientation") + if orientation is not None: + landscape = orientation == "landscape" + if bool(style.IsLandscape) != landscape: + width, height = style.Width, style.Height + style.IsLandscape = landscape + style.Width, style.Height = height, width + if settings.get("fit_to_width") is not None: + style.ScaleToPagesX = int(settings["fit_to_width"]) + if settings.get("fit_to_height") is not None: + style.ScaleToPagesY = int(settings["fit_to_height"]) + if settings.get("scale") is not None: + style.PageScale = int(settings["scale"]) + if settings.get("print_title_rows") is not None: + _, r1, _, r2 = parse_a1_range( + "A" + str(settings["print_title_rows"]).replace("$", "").replace(":", ":A") + ) + sheet.setTitleRows(CellRangeAddress(self.sheet_index(op["sheet"]), 0, r1, 0, r2)) + sheet.setPrintTitleRows(True) + for key, on_prop, content_prop in ( + ("header_center", "HeaderIsOn", "RightPageHeaderContent"), + ("footer_center", "FooterIsOn", "RightPageFooterContent"), + ): + if settings.get(key) is None: + continue + style.setPropertyValue(on_prop, True) + content = style.getPropertyValue(content_prop) + self.fill_header_text(content.CenterText, str(settings[key])) + style.setPropertyValue(content_prop, content) + + def fill_header_text(self, text, value): + """Write OOXML header/footer text, turning &P/&N/&D/&T/&A/&F into fields.""" + text.setString("") + cursor = text.createTextCursor() + buffer = [] + index = 0 + while index < len(value): + char = value[index] + if char == "&" and index + 1 < len(value): + code = value[index + 1] + if code == "&": + buffer.append("&") + index += 2 + continue + service = HF_CODE_SERVICES.get(code.upper()) + if service is not None: + if buffer: + text.insertString(cursor, "".join(buffer), False) + buffer = [] + field = self.doc.createInstance(service) + text.insertTextContent(cursor, field, False) + index += 2 + continue + buffer.append(char) + index += 1 + if buffer: + text.insertString(cursor, "".join(buffer), False) + + def op_chart(self, op): + spec = op.get("chart") or {} + sheet = self.sheet(op["sheet"]) + data_ref = spec.get("data_ref") + if not data_ref: + raise ValueError("chart op requires data_ref") + data_sheet = data_ref.split("!")[0].strip("'") if "!" in data_ref else op["sheet"] + data_area = ( + self.sheet(data_sheet) + .getCellRangeByName(data_ref.split("!")[-1].replace("$", "")) + .RangeAddress + ) + from_col, from_row = parse_a1(spec.get("from") or "B2") + to_col, to_row = parse_a1(spec.get("to") or "H12") + start = sheet.getCellByPosition(from_col, from_row).Position + end = sheet.getCellByPosition(to_col, to_row).Position + rect = Rectangle(start.X, start.Y, max(end.X - start.X, 1), max(end.Y - start.Y, 1)) + charts = sheet.Charts + name = f"Chart{charts.Count + 1}" + while charts.hasByName(name): + name += "_" + charts.addNewByName(name, rect, (data_area,), False, False) + chart_doc = charts.getByName(name).EmbeddedObject + chart_type = str(spec.get("type") or "bar").lower() + if chart_type == "line": + chart_doc.setDiagram(chart_doc.createInstance("com.sun.star.chart.LineDiagram")) + elif chart_type != "bar": + raise ValueError(f"unsupported chart type {chart_type!r}") + categories = spec.get("categories_ref") + if categories: + cat_sheet = categories.split("!")[0].strip("'") if "!" in categories else op["sheet"] + cat_ref = categories.split("!")[-1].replace("$", "") + c1, r1, c2, r2 = parse_a1_range(cat_ref) + representation = f"${cat_sheet}.${col_letter(c1)}${r1 + 1}:${col_letter(c2)}${r2 + 1}" + provider = chart_doc.getDataProvider() + sequence = provider.createDataSequenceByRangeRepresentation(representation) + labeled = self.helper.create("com.sun.star.chart2.data.LabeledDataSequence") + labeled.setValues(sequence) + diagram = chart_doc.getFirstDiagram() + axis = diagram.getCoordinateSystems()[0].getAxisByDimension(0, 0) + scale = axis.getScaleData() + scale.Categories = labeled + axis.setScaleData(scale) + page = sheet.DrawPage + for index in range(page.Count): + shape = page.getByIndex(index) + if shape.ShapeType == "com.sun.star.drawing.OLE2Shape" and shape.PersistName == name: + shape.Anchor = sheet.getCellByPosition(from_col, from_row) + shape.ResizeWithCell = True + shape.Position = Point(start.X, start.Y) + break + + def op_pivot(self, op): + spec = op.get("pivot") or {} + source = spec.get("source_range") or spec.get("data_range") + if not source: + raise ValueError("pivot op requires source_range") + source_sheet = source.split("!")[0].strip("'") if "!" in source else op["sheet"] + source_area = ( + self.sheet(source_sheet) + .getCellRangeByName(source.split("!")[-1].replace("$", "")) + .RangeAddress + ) + target = spec.get("target_cell") or spec.get("range") + if not target: + raise ValueError("pivot op requires target_cell") + target_sheet = target.split("!")[0].strip("'") if "!" in target else op["sheet"] + t_col, t_row = parse_a1(target.split("!")[-1].split(":")[0]) + pivots = self.sheet(target_sheet).DataPilotTables + descriptor = pivots.createDataPilotDescriptor() + descriptor.setSourceRange(source_area) + fields = descriptor.DataPilotFields + orientation = "com.sun.star.sheet.DataPilotFieldOrientation" + for key, kind in ( + ("row_fields", "ROW"), + ("column_fields", "COLUMN"), + ("filter_fields", "PAGE"), + ("data_fields", "DATA"), + ): + for field_name in spec.get(key) or []: + field = fields.getByName(str(field_name)) + field.Orientation = _enum(orientation, kind) + if kind == "DATA": + field.Function = _enum("com.sun.star.sheet.GeneralFunction", "SUM") + name = str(spec.get("name") or f"PivotTable{pivots.Count + 1}") + pivots.insertNewByName( + name, CellAddress(self.sheet_index(target_sheet), t_col, t_row), descriptor + ) diff --git a/tools/external-oracles/remote/README.md b/tools/external-oracles/remote/README.md new file mode 100644 index 0000000..ae9b671 --- /dev/null +++ b/tools/external-oracles/remote/README.md @@ -0,0 +1,82 @@ +# Remote Docker External Oracles + +Runs the write-only `apache-poi` (Java) and `excelize` (Go) ExcelBench adapters +through containers on a remote Docker context, so the benchmark host needs no +local JDK, Go toolchain, or local Docker daemon. + +## Build the images + +The build context uploads from this checkout to the remote daemon. Each +Dockerfile pulls `container_entry.py` from this directory through a named build +context. + +```bash +cd tools/external-oracles/apache-poi +docker --context pc build --build-context oracle-remote=../remote \ + -t excelbench-poi-oracle:5.5.1 . + +cd ../excelize +docker --context pc build --build-context oracle-remote=../remote \ + -t excelbench-excelize-oracle:2.10.1 . +``` + +The POI image runs `build.sh` (which runs `fetch_deps.py`, verifying every +Maven Central jar against its published checksum, then compiles `PoiOracle` and +runs its self-test). The Excelize image runs `go mod verify` and `go test ./...` +against the pinned `go.mod`/`go.sum` before building the helper binary. + +## Run the benchmark + +```bash +EXCELBENCH_ORACLE_DOCKER_CONTEXT=pc \ + excelbench benchmark -t fixtures/excel -o results-dir -a apache-poi -a excelize +``` + +When `EXCELBENCH_ORACLE_DOCKER_CONTEXT` is set, `external_oracle_catalog()` +points the `apache-poi` and `excelize` tools at `docker_oracle.py` with that +context and the image tags above. When it is unset, the catalog is unchanged +and uses the local Java and Go helpers. + +## Transport + +Bind mounts would resolve on the remote host's filesystem, so nothing is +mounted. `docker_oracle.py` reads the oracle request JSON from stdin and: + +1. Base64-embeds the contents of `input_path` (or of an existing `output_path` + when no `input_path` is given, matching the helpers' read fallback) and of + every local file named by `payload.images[].path`, rewriting those paths to + container paths under `/work/in/`. +2. Rewrites `output_path` to `/work/out/`. +3. Runs `docker --context run --rm -i --pull never --network none ` + with the envelope on stdin. `container_entry.py` (the image entrypoint) + writes the embedded files, runs the helper with the rewritten request, and + replies with one JSON envelope holding the helper's exact stdout and stderr + bytes, its return code, and the bytes of the written workbook. +4. Writes the workbook to the original local `output_path`, prints the helper's + stdout unchanged, forwards its stderr, and exits with the helper's return + code, so helper errors surface exactly as they do locally. + +If Docker itself fails (missing image, unreachable context), the wrapper +prints `{"error": "docker_oracle_transport_failed", ...}` and exits with +Docker's non-zero code. Helper containers have no network access and never +pull images implicitly. + +## Runtime versions + +Recorded from the images built on `pc` (linux/amd64) on 2026-10-01. + +| Image | Image ID | Library | Runtime | +| --- | --- | --- | --- | +| `excelbench-poi-oracle:5.5.1` | `ef46106ed14d` | Apache POI 5.5.1 (`poi`, `poi-ooxml`, `poi-ooxml-lite`), xmlbeans 5.3.0 | Eclipse Temurin OpenJDK 21.0.12.1+1 LTS (`javac 21.0.12.1`), Python 3.14.4, Ubuntu 26.04.1 LTS | +| `excelbench-excelize-oracle:2.10.1` | `425caf1a873f` | `github.com/xuri/excelize/v2` v2.10.1 | Go 1.25.14 (static, `CGO_ENABLED=0`), Python 3.13.5, Debian 13 (trixie) | + +Base images are pinned by digest in the Dockerfiles: + +- `eclipse-temurin:21-jdk@sha256:3e3c176ffed168beb42c607be9bc1639b466cf00261a0fb04425562c9d0c5c2b` +- `golang:1.25-trixie@sha256:2c4c60ef415fbfa5e90300722293bef36c5e63fae17570ce18f580af933dbd73` +- `debian:trixie-slim@sha256:a99cfc517144bc59b1978475ec53b46ecabec7e43635402ee5b77cc54cd1b20a` + +The remaining POI runtime jars are the exact set pinned in +`../apache-poi/fetch_deps.py`: commons-compress 1.28.0, commons-io 2.21.0, +commons-lang3 3.18.0, curvesapi 1.08, log4j-api 2.24.3, commons-collections4 +4.5.0, commons-codec 1.20.0, commons-math3 3.6.1, SparseBitSet 1.3. diff --git a/tools/external-oracles/remote/container_entry.py b/tools/external-oracles/remote/container_entry.py new file mode 100755 index 0000000..8d29fc2 --- /dev/null +++ b/tools/external-oracles/remote/container_entry.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +"""In-container side of the remote Docker oracle transport. + +Reads one envelope from stdin, materializes the embedded files inside the +container, runs the baked-in helper command with the rewritten oracle request +on its stdin, and writes one envelope to stdout carrying the helper's exact +stdout/stderr bytes, its return code, and the produced output workbook bytes. + +Envelope in:: + + {"request": {...}, "files": [{"path": "/work/in/x.xlsx", "base64": "..."}]} + +Envelope out:: + + {"protocol": 1, "returncode": 0, "stdout_base64": "...", + "stderr_base64": "...", "output_base64": "..." | null} + +Usage (as the image ENTRYPOINT):: + + container_entry.py --cwd /opt/helper [--timeout 600] -- helper-cmd [args...] +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from base64 import b64decode, b64encode +from pathlib import Path + +PROTOCOL = 1 + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--cwd", required=True) + parser.add_argument("--timeout", type=float, default=600.0) + parser.add_argument("command", nargs=argparse.REMAINDER) + args = parser.parse_args() + command = args.command[1:] if args.command[:1] == ["--"] else args.command + if not command: + parser.error("missing helper command after --") + + envelope = json.loads(sys.stdin.buffer.read()) + request = envelope["request"] + for item in envelope.get("files", []): + path = Path(item["path"]) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(b64decode(item["base64"])) + output_path = request.get("output_path") + if output_path: + Path(output_path).parent.mkdir(parents=True, exist_ok=True) + + try: + completed = subprocess.run( + command, + input=json.dumps(request, sort_keys=True).encode("utf-8"), + capture_output=True, + check=False, + timeout=args.timeout, + cwd=args.cwd, + ) + returncode = completed.returncode + stdout = completed.stdout + stderr = completed.stderr + except subprocess.TimeoutExpired as exc: + returncode = 124 + stdout = exc.stdout or b"" + stderr = (exc.stderr or b"") + ( + f"container helper timed out after {args.timeout:g}s\n".encode() + ) + + output_bytes = None + if output_path and Path(output_path).is_file(): + output_bytes = Path(output_path).read_bytes() + + sys.stdout.write( + json.dumps( + { + "protocol": PROTOCOL, + "returncode": returncode, + "stdout_base64": b64encode(stdout).decode("ascii"), + "stderr_base64": b64encode(stderr).decode("ascii"), + "output_base64": ( + None if output_bytes is None else b64encode(output_bytes).decode("ascii") + ), + } + ) + ) + sys.stdout.flush() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/external-oracles/remote/docker_oracle.py b/tools/external-oracles/remote/docker_oracle.py new file mode 100755 index 0000000..f3e1fc4 --- /dev/null +++ b/tools/external-oracles/remote/docker_oracle.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +"""Run an ExcelBench external-oracle helper inside a container on a Docker context. + +Drop-in replacement for a local helper command: reads the oracle request JSON +from stdin and prints the helper's stdout unchanged, forwards its stderr, and +exits with its return code. Bind mounts would resolve on the remote host, so +every file crosses the wire inside stdin/stdout envelopes instead: + +* ``input_path`` (or an existing ``output_path`` when no ``input_path`` is + given, mirroring the helpers' read fallback) and every ``payload.images[].path`` + that exists locally are base64-embedded and rewritten to container paths. +* ``output_path`` is rewritten to a container path; the bytes the helper wrote + there are copied back to the original local ``output_path``. + +Usage:: + + docker_oracle.py --context pc --image excelbench-poi-oracle:5.5.1 < request.json +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from base64 import b64decode, b64encode +from pathlib import Path +from typing import Any + +IN_DIR = "/work/in" +OUT_DIR = "/work/out" +PROTOCOL = 1 + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--context", required=True, help="docker context name, e.g. pc") + parser.add_argument("--image", required=True) + parser.add_argument("--docker", default="docker", help="docker CLI executable") + args = parser.parse_args() + + request: dict[str, Any] = json.loads(sys.stdin.buffer.read()) + files: list[dict[str, str]] = [] + + def embed(local: Path, container_path: str) -> str: + files.append({"path": container_path, "base64": b64encode(local.read_bytes()).decode()}) + return container_path + + local_output: Path | None = None + output_path = request.get("output_path") + input_path = request.get("input_path") + if output_path: + local_output = Path(output_path) + container_output = f"{OUT_DIR}/{local_output.name}" + request["output_path"] = container_output + if not input_path and local_output.is_file(): + embed(local_output, container_output) + if input_path and Path(input_path).is_file(): + request["input_path"] = embed(Path(input_path), f"{IN_DIR}/input{Path(input_path).suffix}") + + payload = request.get("payload") + if isinstance(payload, dict) and isinstance(payload.get("images"), list): + for index, entry in enumerate(payload["images"]): + if not isinstance(entry, dict): + continue + image_path = entry.get("path") + if isinstance(image_path, str) and image_path and Path(image_path).is_file(): + entry["path"] = embed( + Path(image_path), f"{IN_DIR}/image-{index}{Path(image_path).suffix}" + ) + + command = [ + args.docker, + "--context", + args.context, + "run", + "--rm", + "-i", + "--pull", + "never", + "--network", + "none", + args.image, + ] + envelope_in = json.dumps({"request": request, "files": files}).encode("utf-8") + completed = subprocess.run(command, input=envelope_in, capture_output=True, check=False) + + envelope = _parse_envelope(completed.stdout) + if completed.returncode != 0 or envelope is None: + sys.stderr.buffer.write(completed.stderr) + sys.stdout.write( + json.dumps( + { + "error": "docker_oracle_transport_failed", + "message": ( + f"{' '.join(command)} exited {completed.returncode}: " + f"{completed.stderr.decode('utf-8', 'replace').strip()}" + ), + }, + sort_keys=True, + ) + + "\n" + ) + return completed.returncode or 1 + + output_b64 = envelope.get("output_base64") + if local_output is not None and output_b64 is not None: + local_output.parent.mkdir(parents=True, exist_ok=True) + local_output.write_bytes(b64decode(output_b64)) + sys.stderr.buffer.write(completed.stderr) + sys.stderr.buffer.write(b64decode(envelope["stderr_base64"])) + sys.stdout.buffer.write(b64decode(envelope["stdout_base64"])) + sys.stdout.flush() + return int(envelope["returncode"]) + + +def _parse_envelope(stdout: bytes) -> dict[str, Any] | None: + try: + envelope = json.loads(stdout) + except ValueError: + return None + if not isinstance(envelope, dict) or envelope.get("protocol") != PROTOCOL: + return None + return envelope + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/external-oracles/sheetjs/README.md b/tools/external-oracles/sheetjs/README.md new file mode 100644 index 0000000..dddaf87 --- /dev/null +++ b/tools/external-oracles/sheetjs/README.md @@ -0,0 +1,104 @@ +# SheetJS CE helper (`sheetjs` adapter) + +Node helper behind `src/excelbench/harness/adapters/sheetjs_adapter.py`. It drives +SheetJS Community Edition (npm package `xlsx`) through its public API only: +`XLSX.readFile`, `XLSX.utils`, and `XLSX.writeFile`. + +## Install + +```sh +cd tools/external-oracles/sheetjs +npm ci +``` + +`package.json` pins SheetJS CE **0.20.3** from the official CDN tarball +(`https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz`); `package-lock.json` +records its integrity hash. The npm registry `xlsx` package is stale (0.18.x), so +do not replace the CDN URL with a registry version. The reported version comes +from `XLSX.version` at runtime. Verified with Node 22. + +## Protocol + +The Python adapter runs `node sheetjs-adapter.cjs` with this directory as cwd, +writes one JSON request on stdin, and reads one JSON object from stdout. Failures +print `{"error": "sheetjs_failed", "message": ...}` and exit 1. The full contract +lives with the Python `JsonModelAdapter`. + +| Operation | What the helper does | +| --- | --- | +| `describe` | Returns `library: "sheetjs"`, `version` from `XLSX.version`, capabilities `read`/`write`/`modify`, and the `unsupported_write` map below. | +| `read_model` | `XLSX.readFile(path, {cellFormula, cellNF, cellStyles, cellDates, UTC, sheetStubs})`, then reports cell values (`t`/`v`/`f`/`w`), number formats (`z`), solid fills (`s.fgColor`), `!rows` heights (`hpt`), raw `!cols` widths, `!merges`, hyperlinks (`l`), comments (`c`), and `Workbook.Names`. | +| `write_model` | Builds a workbook with `XLSX.utils.book_new` / `sheet_new` / `book_append_sheet`, replays each op on the cell objects and sheet keys, and saves with `XLSX.writeFile`. | +| `mutate` | `XLSX.readFile` on the template, `XLSX.utils.sheet_add_aoa` for each mutated cell, then `XLSX.writeFile`. This is SheetJS's real modify path: it parses the package into its object model and writes a brand-new package, so parts SheetJS does not model are not carried over. | + +### Value mapping + +- Formula cells report `=` plus `f`. A formula whose cached result is an error + (`t: "e"`) reports type `error` with the error literal, per the contract. +- With `cellDates` and `UTC`, date-formatted serials arrive as UTC `Date` + objects; midnight values report `date`, others `datetime`. +- Written dates are `t: "d"` cells with an ISO string. SheetJS converts them to + serials and applies its default date format (`m/d/yy`) when no `z` is set. +- Error ops are written as the formulas the contract lists (`1/0`, `NA()`, ...). + +### Partial support (reported, not declared unsupported) + +- **Cell format, read:** with `cellStyles`, the CE XLSX reader attaches only the + cell fill to `cell.s`. The helper reports `bg_color` (solid fills) and + `number_format`; font, alignment, wrap, rotation, and indent keys are absent. +- **Cell format, write:** the CE writer emits only number formats in cell + styles (`get_cell_style` builds xfs with `fontId`/`fillId`/`borderId` 0). Only + `number_format` is written (`XLSX.utils.cell_set_number_format`); other keys are + dropped and logged to stderr. +- **Row heights, write:** `!rows` is serialized inside ``, which the + CE writer skips when the sheet has no `!ref` (no cells). Heights set on an + otherwise empty sheet are therefore lost. +- **Page setup:** the CE XLSX reader and writer handle only `!margins`. The + helper reports and writes `print_title_rows` through the `_xlnm.Print_Titles` + defined name in `Workbook.Names`. Orientation, fit-to, scale, and header/footer + have no CE API; they are omitted on read and dropped (logged to stderr) on write. +- **Named ranges:** Excel built-in `_xlnm.*` names are excluded from + `named_ranges` because they are not user-defined ranges. +- **Comments:** one entry per cell from `cell.c[0]` (`a` author, `t` text, + `T` threaded flag). + +## Unsupported declarations + +Read side (`model.unsupported`): + +| Feature key | Reason | +| --- | --- | +| `cell_border` | SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s | +| `conditional_formats` | SheetJS CE has no conditional formatting API; the XLSX reader skips `` | +| `data_validations` | SheetJS CE has no data validation API; the XLSX reader skips `` | +| `images` | SheetJS CE does not parse worksheet drawings, so embedded images are not exposed | +| `pivot_tables` | SheetJS CE does not parse pivot table parts | +| `freeze_panes` | SheetJS CE parses `` only for zoom and right-to-left; panes are not exposed | +| `tables` | SheetJS CE does not parse table parts (`xl/tables/*.xml`); only the sheet autofilter is exposed | +| `sheet_protection` | SheetJS CE's XLSX reader does not parse ``; `ws['!protect']` is populated only for XLS/XLSB/XLML inputs | +| `chart_anchors` | SheetJS CE does not parse charts or drawing anchors in worksheets | + +Write side (`describe.unsupported_write`): + +| Op | Reason | +| --- | --- | +| `cell_border` | SheetJS CE has no border API; the SheetJS CE writer only emits number formats in cell styles | +| `conditional_format` | SheetJS CE has no conditional formatting API; the XLSX writer emits no `` | +| `data_validation` | SheetJS CE has no data validation API; the XLSX writer emits no `` | +| `image` | SheetJS CE cannot embed images (drawing parts are not written) | +| `pivot` | SheetJS CE cannot create pivot tables | +| `freeze` | SheetJS CE's XLSX writer emits `` without a `` element, so panes cannot be set | +| `table` | SheetJS CE cannot create table parts; only a sheet autofilter (`ws['!autofilter']`) is writable | +| `chart` | SheetJS CE cannot create charts | + +Sheet protection is writable: `ws['!protect']` keys mirror the raw +`` attributes (true means blocked), and `password` is hashed by +SheetJS into the legacy `password` attribute. + +## Smoke + +From the ExcelBench repo root: + +```sh +excelbench benchmark -t fixtures/excel -o /tmp/smoke-sheetjs -a sheetjs +``` diff --git a/tools/external-oracles/sheetjs/package-lock.json b/tools/external-oracles/sheetjs/package-lock.json new file mode 100644 index 0000000..94e57e6 --- /dev/null +++ b/tools/external-oracles/sheetjs/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "excelbench-sheetjs-adapter", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "excelbench-sheetjs-adapter", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" + } + }, + "node_modules/xlsx": { + "version": "0.20.3", + "resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", + "integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==", + "license": "Apache-2.0", + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + } + } +} diff --git a/tools/external-oracles/sheetjs/package.json b/tools/external-oracles/sheetjs/package.json new file mode 100644 index 0000000..ccddf01 --- /dev/null +++ b/tools/external-oracles/sheetjs/package.json @@ -0,0 +1,11 @@ +{ + "name": "excelbench-sheetjs-adapter", + "version": "0.1.0", + "private": true, + "description": "SheetJS Community Edition helper for the ExcelBench sheetjs adapter", + "license": "MIT", + "type": "commonjs", + "dependencies": { + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" + } +} diff --git a/tools/external-oracles/sheetjs/sheetjs-adapter.cjs b/tools/external-oracles/sheetjs/sheetjs-adapter.cjs new file mode 100755 index 0000000..9c500c4 --- /dev/null +++ b/tools/external-oracles/sheetjs/sheetjs-adapter.cjs @@ -0,0 +1,582 @@ +#!/usr/bin/env node +"use strict"; + +/* + * ExcelBench helper for SheetJS Community Edition (npm `xlsx`). + * + * Speaks the JSON-model helper protocol: one request on stdin, one JSON object + * on stdout. Everything reported or written goes through the public SheetJS + * API (`XLSX.readFile`, `XLSX.utils`, `XLSX.writeFile`). Features the CE build + * cannot read or write are declared unsupported with the concrete reason. + */ + +const fs = require("fs"); +const XLSX = require("xlsx"); + +const LIBRARY = "sheetjs"; + +/* Read options: expose every cell-level detail SheetJS CE can parse. */ +const READ_OPTIONS = { + cellFormula: true, // `f` formula text + cellNF: true, // `z` number format string + cellStyles: true, // `s` fill, `!cols` widths, `!rows` heights + cellDates: true, // date-formatted serials become `t: "d"` Date values + UTC: true, // interpret Excel date serials as UTC instants + sheetStubs: true, // keep formatted / commented / linked empty cells +}; + +/* Template-mutation lane: keep stored serials as numbers so untouched date + * cells are not round-tripped through Date objects. */ +const MUTATE_READ_OPTIONS = { + cellFormula: true, + cellNF: true, + cellStyles: true, +}; + +const WRITE_OPTIONS = { bookType: "xlsx", compression: true }; + +const CE_STYLE_WRITE = + "the SheetJS CE writer only emits number formats in cell styles"; + +const UNSUPPORTED_READ = { + cell_border: + "SheetJS CE does not expose cell borders: with cellStyles the XLSX reader attaches only the fill to cell.s", + conditional_formats: + "SheetJS CE has no conditional formatting API; the XLSX reader skips ", + data_validations: + "SheetJS CE has no data validation API; the XLSX reader skips ", + images: + "SheetJS CE does not parse worksheet drawings, so embedded images are not exposed", + pivot_tables: "SheetJS CE does not parse pivot table parts", + freeze_panes: + "SheetJS CE parses only for zoom and right-to-left; panes are not exposed", + tables: + "SheetJS CE does not parse table parts (xl/tables/*.xml); only the sheet autofilter is exposed", + sheet_protection: + "SheetJS CE's XLSX reader does not parse ; ws['!protect'] is populated only for XLS/XLSB/XLML inputs", + chart_anchors: + "SheetJS CE does not parse charts or drawing anchors in worksheets", +}; + +const UNSUPPORTED_WRITE = { + cell_border: `SheetJS CE has no border API; ${CE_STYLE_WRITE}`, + conditional_format: + "SheetJS CE has no conditional formatting API; the XLSX writer emits no ", + data_validation: + "SheetJS CE has no data validation API; the XLSX writer emits no ", + image: "SheetJS CE cannot embed images (drawing parts are not written)", + pivot: "SheetJS CE cannot create pivot tables", + freeze: + "SheetJS CE's XLSX writer emits without a element, so panes cannot be set", + table: + "SheetJS CE cannot create table parts; only a sheet autofilter (ws['!autofilter']) is writable", + chart: "SheetJS CE cannot create charts", +}; + +/* ------------------------------------------------------------------------ */ +/* helpers */ +/* ------------------------------------------------------------------------ */ + +function fail(message) { + process.stdout.write( + JSON.stringify({ error: "sheetjs_failed", message: String(message) }) + "\n" + ); + process.exit(1); +} + +function readStdin() { + return fs.readFileSync(0, "utf8"); +} + +function pad2(n) { + return String(n).padStart(2, "0"); +} + +function dateParts(d) { + /* SheetJS hands back Date objects in UTC (READ_OPTIONS.UTC). Round to the + * nearest second to drop floating-point serial noise. */ + const t = new Date(Math.round(d.getTime() / 1000) * 1000); + const day = `${String(t.getUTCFullYear()).padStart(4, "0")}-${pad2( + t.getUTCMonth() + 1 + )}-${pad2(t.getUTCDate())}`; + const hasTime = + t.getUTCHours() !== 0 || t.getUTCMinutes() !== 0 || t.getUTCSeconds() !== 0; + const time = `${pad2(t.getUTCHours())}:${pad2(t.getUTCMinutes())}:${pad2( + t.getUTCSeconds() + )}`; + return { day, hasTime, time }; +} + +function hexColor(color) { + if (!color || typeof color.rgb !== "string") return null; + const rgb = color.rgb.replace(/^#/, ""); + if (rgb.length < 6) return null; + return `#${rgb.slice(-6).toUpperCase()}`; +} + +function sheetCellEntries(ws) { + return Object.keys(ws).filter((key) => key[0] !== "!"); +} + +/* ------------------------------------------------------------------------ */ +/* read_model */ +/* ------------------------------------------------------------------------ */ + +function modelValue(cell) { + switch (cell.t) { + case "z": + return null; + case "e": + return { + type: "error", + value: cell.w || XLSX.utils.format_cell(cell), + formula: cell.f ? `=${cell.f}` : null, + }; + default: + break; + } + if (typeof cell.f === "string" && cell.f.length > 0) { + const formula = `=${cell.f}`; + return { type: "formula", value: formula, formula }; + } + switch (cell.t) { + case "s": + return { type: "string", value: cell.v == null ? "" : String(cell.v), formula: null }; + case "n": + return { type: "number", value: cell.v, formula: null }; + case "b": + return { type: "boolean", value: Boolean(cell.v), formula: null }; + case "d": { + const parts = dateParts(cell.v instanceof Date ? cell.v : new Date(cell.v)); + if (parts.hasTime) { + return { type: "datetime", value: `${parts.day}T${parts.time}`, formula: null }; + } + return { type: "date", value: parts.day, formula: null }; + } + default: + return null; + } +} + +function modelFormat(cell) { + const fmt = {}; + if (typeof cell.z === "string") fmt.number_format = cell.z; + else if (typeof cell.z === "number") fmt.number_format = XLSX.SSF.get_table()[cell.z]; + const fill = cell.s; + if (fill && fill.patternType === "solid") { + const color = hexColor(fill.fgColor); + if (color) fmt.bg_color = color; + } + return fmt; +} + +function readPrintTitleRows(names, sheetIndex) { + for (const name of names) { + if (name.Name !== "_xlnm.Print_Titles" || name.Sheet !== sheetIndex) continue; + for (const part of String(name.Ref || "").split(",")) { + const addr = part.slice(part.lastIndexOf("!") + 1); + if (/^\$?\d+:\$?\d+$/.test(addr)) return addr; + } + } + return null; +} + +function readSheet(wb, sheetName, sheetIndex) { + const ws = wb.Sheets[sheetName]; + const names = (wb.Workbook && wb.Workbook.Names) || []; + const cells = {}; + const hyperlinks = []; + const comments = []; + + for (const addr of sheetCellEntries(ws)) { + const cell = ws[addr]; + if (!cell || typeof cell !== "object") continue; + const entry = {}; + const value = modelValue(cell); + if (value) entry.value = value; + const fmt = modelFormat(cell); + if (Object.keys(fmt).length > 0) entry.format = fmt; + if (Object.keys(entry).length > 0) cells[addr] = entry; + + if (cell.l && typeof cell.l.Target === "string") { + const internal = Boolean(cell.l.Rel && cell.l.Rel.TargetMode === "Internal"); + hyperlinks.push({ + cell: addr, + target: internal ? cell.l.Target.replace(/^#/, "") : cell.l.Target, + display: cell.t === "z" ? null : cell.w != null ? cell.w : String(cell.v), + tooltip: cell.l.Tooltip != null ? String(cell.l.Tooltip) : null, + internal, + }); + } + if (Array.isArray(cell.c) && cell.c.length > 0) { + const first = cell.c[0]; + comments.push({ + cell: addr, + text: first.t == null ? "" : String(first.t), + author: first.a != null ? String(first.a) : null, + threaded: Boolean(first.T), + }); + } + } + + const rowHeights = {}; + (ws["!rows"] || []).forEach((row, idx) => { + if (row && typeof row.hpt === "number") rowHeights[String(idx + 1)] = row.hpt; + }); + const columnWidths = {}; + (ws["!cols"] || []).forEach((col, idx) => { + if (col && typeof col.width === "number" && !Number.isNaN(col.width)) { + columnWidths[XLSX.utils.encode_col(idx)] = col.width; + } + }); + const merged = (ws["!merges"] || []).map((rng) => XLSX.utils.encode_range(rng)); + + const pageSetup = {}; + const titles = readPrintTitleRows(names, sheetIndex); + if (titles) pageSetup.print_title_rows = titles; + + return { + name: sheetName, + cells, + row_heights: rowHeights, + column_widths: columnWidths, + merged_ranges: merged, + hyperlinks, + comments, + page_setup: pageSetup, + }; +} + +function readModel(inputPath) { + const wb = XLSX.readFile(inputPath, READ_OPTIONS); + const names = (wb.Workbook && wb.Workbook.Names) || []; + const namedRanges = []; + for (const name of names) { + /* `_xlnm.*` are Excel built-in names (print area/titles, filter + * database), not user-defined named ranges. */ + if (String(name.Name).startsWith("_xlnm.")) continue; + const local = name.Sheet != null; + namedRanges.push({ + name: String(name.Name), + scope: local ? "sheet" : "workbook", + sheet: local ? wb.SheetNames[name.Sheet] || null : null, + refers_to: String(name.Ref || ""), + }); + } + return { + unsupported: UNSUPPORTED_READ, + named_ranges: namedRanges, + sheets: wb.SheetNames.map((sheetName, idx) => readSheet(wb, sheetName, idx)), + }; +} + +/* ------------------------------------------------------------------------ */ +/* write_model */ +/* ------------------------------------------------------------------------ */ + +const 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", +}; + +function requireSheet(wb, name) { + const ws = wb.Sheets[name]; + if (!ws) throw new Error(`worksheet not found: ${name}`); + return ws; +} + +function extendRef(ws, addr) { + const pos = XLSX.utils.decode_cell(addr); + if (!ws["!ref"]) { + ws["!ref"] = XLSX.utils.encode_range(pos, pos); + return; + } + const range = XLSX.utils.decode_range(ws["!ref"]); + range.s.r = Math.min(range.s.r, pos.r); + range.s.c = Math.min(range.s.c, pos.c); + range.e.r = Math.max(range.e.r, pos.r); + range.e.c = Math.max(range.e.c, pos.c); + ws["!ref"] = XLSX.utils.encode_range(range); +} + +function cellFor(ws, addr) { + const ref = String(addr).toUpperCase(); + const cell = XLSX.utils.sheet_get_cell(ws, ref); + extendRef(ws, ref); + return cell; +} + +function setValue(cell, t, v) { + delete cell.f; + delete cell.F; + delete cell.w; + cell.t = t; + cell.v = v; +} + +function setFormula(cell, formula) { + delete cell.v; + delete cell.w; + delete cell.t; + cell.f = String(formula).replace(/^=/, ""); +} + +function applyCellValue(ws, op) { + const cell = cellFor(ws, op.cell); + const value = op.value; + switch (op.type) { + case "string": + setValue(cell, "s", value == null ? "" : String(value)); + break; + case "number": + setValue(cell, "n", Number(value)); + break; + case "boolean": + setValue(cell, "b", Boolean(value)); + break; + case "date": + case "datetime": + /* SheetJS date cells: `t: "d"` with an ISO string; the writer converts + * it to a serial and applies the default date format when none set. */ + setValue(cell, "d", String(value)); + break; + case "formula": + setFormula(cell, op.formula != null ? op.formula : value); + break; + case "error": { + const formula = ERROR_FORMULAS[String(value)]; + if (!formula) throw new Error(`no formula known to produce error ${value}`); + setFormula(cell, formula); + break; + } + case "blank": + setValue(cell, "z", undefined); + delete cell.v; + break; + default: + throw new Error(`unsupported cell value type: ${op.type}`); + } +} + +function applyCellFormat(ws, op) { + const fmt = op.format || {}; + const cell = cellFor(ws, op.cell); + if (fmt.number_format != null) { + XLSX.utils.cell_set_number_format(cell, String(fmt.number_format)); + } + const dropped = Object.keys(fmt).filter((key) => key !== "number_format"); + if (dropped.length > 0) { + process.stderr.write( + `sheetjs: ${op.sheet}!${op.cell} format keys not writable (${CE_STYLE_WRITE}): ${dropped.join(", ")}\n` + ); + } +} + +function applyHyperlink(ws, op) { + const link = op.link || {}; + const cell = cellFor(ws, link.cell); + if (link.display != null) setValue(cell, "s", String(link.display)); + const tooltip = link.tooltip != null ? String(link.tooltip) : undefined; + if (link.internal) { + XLSX.utils.cell_set_internal_link(cell, String(link.target).replace(/^#/, ""), tooltip); + } else { + XLSX.utils.cell_set_hyperlink(cell, String(link.target), tooltip); + } +} + +function applyComment(ws, op) { + const comment = op.comment || {}; + if (!comment.cell || comment.text == null) return; + const cell = cellFor(ws, comment.cell); + XLSX.utils.cell_add_comment(cell, String(comment.text), comment.author || undefined); +} + +function workbookNames(wb) { + if (!wb.Workbook) wb.Workbook = {}; + if (!wb.Workbook.Names) wb.Workbook.Names = []; + return wb.Workbook.Names; +} + +function quoteSheet(name) { + return `'${String(name).replace(/'/g, "''")}'`; +} + +function applyNamedRange(wb, op) { + const nr = op.named_range || {}; + if (!nr.name || !nr.refers_to) return; + const entry = { Name: String(nr.name), Ref: String(nr.refers_to).replace(/^=/, "") }; + if (nr.scope === "sheet") { + const idx = wb.SheetNames.indexOf(op.sheet); + if (idx < 0) throw new Error(`worksheet not found: ${op.sheet}`); + entry.Sheet = idx; + } + workbookNames(wb).push(entry); +} + +function applyProtection(ws, op) { + const cfg = op.settings || {}; + if (!cfg.protected) { + delete ws["!protect"]; + return; + } + /* SheetJS `!protect` keys mirror the raw attributes: + * true means the action is blocked, matching the op semantics. */ + const protect = {}; + const keys = { + format_cells: "formatCells", + insert_rows: "insertRows", + select_locked_cells: "selectLockedCells", + select_unlocked_cells: "selectUnlockedCells", + sort: "sort", + auto_filter: "autoFilter", + }; + for (const [src, dst] of Object.entries(keys)) { + if (cfg[src] != null) protect[dst] = Boolean(cfg[src]); + } + if (cfg.password) protect.password = String(cfg.password); + ws["!protect"] = protect; +} + +function applyPageSetup(wb, op) { + const cfg = op.settings || {}; + if (cfg.print_title_rows != null) { + const idx = wb.SheetNames.indexOf(op.sheet); + if (idx < 0) throw new Error(`worksheet not found: ${op.sheet}`); + workbookNames(wb).push({ + Name: "_xlnm.Print_Titles", + Sheet: idx, + Ref: `${quoteSheet(op.sheet)}!${cfg.print_title_rows}`, + }); + } + const dropped = Object.keys(cfg).filter( + (key) => key !== "print_title_rows" && cfg[key] != null + ); + if (dropped.length > 0) { + process.stderr.write( + `sheetjs: ${op.sheet} page setup keys not writable (SheetJS CE writes no /): ${dropped.join(", ")}\n` + ); + } +} + +function writeModel(outputPath, ops) { + const wb = XLSX.utils.book_new(); + for (const op of ops) { + const reason = UNSUPPORTED_WRITE[op.op]; + if (reason) throw new Error(`${op.op}: ${reason}`); + switch (op.op) { + case "add_sheet": + XLSX.utils.book_append_sheet(wb, XLSX.utils.sheet_new(), String(op.name)); + break; + case "cell_value": + applyCellValue(requireSheet(wb, op.sheet), op); + break; + case "cell_format": + applyCellFormat(requireSheet(wb, op.sheet), op); + break; + case "row_height": { + const ws = requireSheet(wb, op.sheet); + if (!ws["!rows"]) ws["!rows"] = []; + const idx = Number(op.row) - 1; + ws["!rows"][idx] = Object.assign(ws["!rows"][idx] || {}, { hpt: Number(op.height) }); + break; + } + case "column_width": { + const ws = requireSheet(wb, op.sheet); + if (!ws["!cols"]) ws["!cols"] = []; + ws["!cols"][XLSX.utils.decode_col(String(op.column))] = { width: Number(op.width) }; + break; + } + case "merge": { + const ws = requireSheet(wb, op.sheet); + if (!ws["!merges"]) ws["!merges"] = []; + ws["!merges"].push(XLSX.utils.decode_range(String(op.range))); + break; + } + case "hyperlink": + applyHyperlink(requireSheet(wb, op.sheet), op); + break; + case "comment": + applyComment(requireSheet(wb, op.sheet), op); + break; + case "named_range": + applyNamedRange(wb, op); + break; + case "protection": + applyProtection(requireSheet(wb, op.sheet), op); + break; + case "page_setup": + applyPageSetup(wb, op); + break; + default: + throw new Error(`unknown write op: ${op.op}`); + } + } + if (wb.SheetNames.length === 0) throw new Error("write_model received no add_sheet op"); + XLSX.writeFile(wb, outputPath, WRITE_OPTIONS); +} + +/* ------------------------------------------------------------------------ */ +/* mutate */ +/* ------------------------------------------------------------------------ */ + +function mutate(inputPath, outputPath, mutations) { + const wb = XLSX.readFile(inputPath, MUTATE_READ_OPTIONS); + for (const m of mutations) { + const ws = requireSheet(wb, m.sheet); + /* sheet_add_aoa is SheetJS's documented way to set values in an existing + * sheet; it keeps the target cell's number format. */ + XLSX.utils.sheet_add_aoa(ws, [[m.value]], { origin: String(m.cell).toUpperCase() }); + } + XLSX.writeFile(wb, outputPath, WRITE_OPTIONS); +} + +/* ------------------------------------------------------------------------ */ +/* dispatch */ +/* ------------------------------------------------------------------------ */ + +function main() { + let request; + try { + request = JSON.parse(readStdin()); + } catch (err) { + fail(`invalid JSON request on stdin: ${err.message}`); + } + const payload = request.payload || {}; + try { + switch (request.operation) { + case "describe": + return { + library: LIBRARY, + version: XLSX.version, + capabilities: ["read", "write", "modify"], + unsupported_write: UNSUPPORTED_WRITE, + }; + case "read_model": + if (!request.input_path) throw new Error("read_model requires input_path"); + return { model: readModel(request.input_path) }; + case "write_model": + if (!request.output_path) throw new Error("write_model requires output_path"); + writeModel(request.output_path, payload.ops || []); + return { written: request.output_path }; + case "mutate": + if (!request.input_path || !request.output_path) { + throw new Error("mutate requires input_path and output_path"); + } + mutate(request.input_path, request.output_path, payload.mutations || []); + return { written: request.output_path }; + default: + throw new Error(`unknown operation: ${request.operation}`); + } + } catch (err) { + fail(err instanceof Error ? err.message : err); + } + return null; +} + +const result = main(); +process.stdout.write(JSON.stringify(result) + "\n");