跳至主要內容

XTL 符合性套件

此目錄存放 符合性語料庫——也就是任何 XTL 實作要主張符合性時都必須通過的測試案例(fixture)集合。語料庫是 XTL 行為的可執行定義。

目錄結構

conformance/
├── README.md ← 本檔案
├── AUTHORING.md ← 如何新增 fixture(避開「以 JS 為真」的陷阱)
├── runner-protocol.md ← 實作端應如何執行整套套件
└── fixtures/
└── <NNN>-<slug>/
├── template.xlsx
├── data.xlsx
├── expected.xlsx ← 正規的預期輸出(單檔案情境)
├── expected/ ← 或是一整個目錄的檔案(多檔案或零輸出情境)
│ └── *.xlsx
├── no expected output ← 給 expected_error fixture 使用
├── no static expected ← 給 expected_dynamic fixture 使用
└── meta.yaml ← 描述、規格章節參照、標籤

「通過」的定義

對於靜態輸出的 fixture:當實作在輸入 template.xlsxdata.xlsx 後,所產生的輸出與 expected.xlsx(或 expected/ 目錄的內容)一致時,即視為通過。階段 1 執行器 MAY 比對較高層的工作表/儲存格值。階段 2 執行器則在對 OOXML zip 進行 正規化(canonical normalization) 後,比對位元組層級等價的活頁簿內容:

  • zip 內的檔案依名稱排序
  • XML 以決定性的正規形式序列化
  • 文字 run 之間的空白被保留
  • 產生器中繼資料被剝除(creator、modifiedBy、lastModified)

關於比對階段與正規化規則,請見 runner-protocol.md

對於錯誤 fixture:當實作回報的錯誤訊息包含該 fixture 的 expected_error 文字時,即視為通過。錯誤 fixture 不包含 expected.xlsx,也沒有 expected/ 目錄。

對於動態 fixture:當實作的輸出符合 meta.yamlexpected_dynamic 所宣告的動態斷言時,即視為通過。動態 fixture 不包含 expected.xlsx,也沒有 expected/ 目錄。

版本管理

每個 fixture 目錄的 meta.yaml 都會宣告其所需的最低規格版本(spec_version: 0.1)。實作會回報自己對齊的規格版本,套件再依此篩選 fixture。

靜態輸出 fixture MAY 另外宣告 comparison_stage。該欄位預設為 1;需要正規 OOXML 比對的 fixture 則宣告 comparison_stage: 2

Fixture 中繼資料

語料庫使用的 meta.yaml 欄位如下:

欄位必填適用對象意義
description全部 fixturefixture 所宣告的一行式契約。
spec_section全部 fixture定義此行為的規格或 ADR 章節。
spec_version全部 fixture此 fixture 所要求的最低 XTL 版本。
tags全部 fixture用於報告與聚焦執行的可篩選分類。
verified_by全部 fixture獨立的撰寫驗證方式,例如 handmanual-script
expected_warnings全部 fixture實作應發出的穩定警告子字串。
expected_error錯誤 fixture穩定的錯誤子字串;省略靜態預期輸出。
expected_dynamic動態 fixture動態斷言種類;目前為 utc_today
dynamic_cellsexpected_dynamic 同列動態 fixture由執行器計算的工作表/儲存格/格式斷言。
comparison_stage靜態輸出 fixture最低比對階段;預設為 1,OOXML 敏感檢查請設為 2
skip_reason全部 fixture暫時略過已知失效 fixture 的原因。

expected_errorexpected_dynamic 互斥。靜態輸出 fixture 使用 expected.xlsxexpected/;空的 expected/ 目錄代表零個輸出檔。錯誤 fixture 與動態 fixture 均省略靜態預期輸出。

Fixture 目錄

XTL 0.1 啟動版語料庫目前包含下列 fixture:

IDFixture契約
001bracket-substitution單一中括號的來源欄位運算式,會為每一筆來源資料列輸出一列。
002if-functionIF(condition, then, else) 會在目前資料列內評估比較運算。
003list-sheet-filter@filter [field] in _ListSheet 保留符合的列,並從輸出移除清單工作表。
004repeat-right-default@repeat right 未明示數量時,預設 colSpan = 1
005round-half-away-from-zeroROUND() 採用 Excel 風格的「四捨五入遠離零」規則。
006filename-forbidden-chars禁用的檔名字元會被替換為 _
007filename-reserved-nameWindows 保留裝置基底檔名會加上單一結尾 _
008numfmt-numeric-string-coercion數值範本格式會將數值型字串強制轉換為數字。
009numfmt-date-string-coercion日期範本格式會將類日期字串強制轉換為日期值。
010numfmt-text-format-coercion文字格式 @ 會將單一運算式值強制轉換為字串。
011text-date-formatTEXT(date, "YYYY-MM-DD") 以 XTL 日期記號回傳字串。
012text-number-formatTEXT(number, format) 支援 XTL 0.1 數值格式的最小子集。
013rich-text-template-expression富文字範本儲存格在運算式偵測前,會先把各 text run 串接起來解析。
014source-formula-cached-result來源公式儲存格使用快取結果,XTL 不會重新計算。
015source-sheet-prefix-first-matchsource_sheet 前綴樣式會選擇活頁簿順序中第一個符合的工作表。
016text-number-negative-rounding數值 TEXT() 格式對負數 .5 邊界採用「四捨五入遠離零」。
017source-sheet-prefix-no-match-error找不到符合的 source_sheet 前綴時,回報穩定錯誤。
018source-formula-missing-cached-result-error來源公式儲存格若沒有快取結果,回報穩定錯誤。
019filename-empty-basename-error檔名清理會對空白基底檔名回報錯誤。
020filename-length-overflow-error檔名清理會對超過 255 位元組限制者回報錯誤。
021numfmt-number-coercion-error數值範本格式於強制轉換失敗時回報錯誤。
022numfmt-date-coercion-error日期範本格式於強制轉換失敗時回報錯誤。
023today-utc-dynamicTODAY() 透過動態斷言渲染執行器啟動當下的 UTC 日期。
024stage2-merge-preservation階段 2 比對驗證資料展開區塊下方的合併範圍被保留。
025stage2-style-numfmt-preservation階段 2 比對驗證渲染儲存格保留範本的樣式與 numFmt。
026stage2-splice-merge-style-preservation階段 2 比對驗證列展開後,位移的合併與帶樣式/數值格式的渲染儲存格皆被保留。
027stage2-cross-writer-canonicalization階段 2 比對驗證已知的 OOXML 書寫器差異,能正規化為相同的活頁簿內容。
028source-table-row-shorthandsource_table = N 選擇第 N 列作為來源欄名,並從其下方讀取資料。
029source-table-open-rangesource_table = B3:D 選擇欄區間,並向下讀至所用列尾。
030source-table-finite-rangesource_table = B3:D4 在宣告的結束列就停止讀取。
031source-table-zero-data-rangesource_table = B3:D3 有效,會產生零個來源資料列。
032source-table-empty-column-name-error所選範圍內若出現空白來源欄名,回報穩定錯誤。
033source-table-duplicate-column-name-error重複的來源欄名回報穩定錯誤。
034source-table-invalid-selector-error像是第零列這類無效選擇器,回報穩定錯誤。
035source-table-rich-text-header富文字的來源欄名儲存格會先串接,再進行 source_table 解析。
036source-table-formula-header公式型來源欄名儲存格使用快取結果。
037source-table-formula-header-missing-cache-error沒有快取結果的公式型來源欄名儲存格,回報穩定錯誤。
038source-sheet-exact-match-beats-prefixsource_sheet 完全相符優先於前綴樣式。
039source-sheet-default-first-worksheet若省略 source_sheet,採用活頁簿順序中的第一個工作表。
040list-sheet-hidden-states-removed隱藏與深度隱藏的清單工作表,依然會從輸出活頁簿中移除。
041row-function-inside-repeat-blockROW() 在 repeat 區塊內回傳目前渲染資料列的 1-起始索引。
042row-function-outside-repeat-block-error在 repeat 區塊外呼叫 ROW() 會回報穩定錯誤。
043ifempty-functionIFEMPTY() 對空值回傳替代值,對非空值原樣放行。
044sort-and-top-order@sort 先於 @top 執行,因此前 N 列來自已排序的集合。
045list-sheet-not-in-filter@filter ... !in _Sheet 保留值不在清單工作表中的列,並從輸出移除該清單工作表。
046count-field-non-emptyCOUNT([field]) 對目前的列集合計算非空值。
047aggregate-functions核心彙總函式作用於目前渲染的列集合。
048if-and-comparison-boundaries比較運算子驅動 IF()@filter 在零邊界附近的行為。
049filename-sanitization-warning對已渲染檔名進行清理時,會發出警告但不改變輸出語意。
050empty-ifempty-whitespace-only依 ADR-0007,IFEMPTY 將純空白字串視為空值。
051empty-ifempty-zero-not-empty依 ADR-0007,IFEMPTY 保留數字 0;數字永遠不是空值。
052empty-count-field-whitespace-zero-false依 ADR-0007,COUNT([field]) 計算非空值——空白為空,0 與 FALSE 視為非空。
053empty-row-skip-whitespace-only依 ADR-0007,所有儲存格皆為空的來源列被跳過,包含純空白儲存格。
054empty-list-membership清單工作表讀取時會丟棄空白項目;依 ADR-0007,空白來源值永遠不會符合 @filter ... in _Sheet
055if-truthy-zero-and-empty依 ADR-0008,IF 將 0 與空值視為假;非零數字、非空字串與 TRUE 視為真。
056if-truthy-string-zero-not-specialIF("0", …)IF("false", …) 走真值分支——對於字串型旗標沒有特例。
057if-truthy-boolean依 ADR-0008,布林型來源儲存格直接驅動 IF 的真值判斷。
058if-comparison-result依 ADR-0008,比較運算式的布林結果直接驅動 IF 的真值判斷。
059compare-numeric-string-vs-number依 ADR-0009,比較時會在共用的 compareValues 下解析數字與數值字串。
060compare-string-codepoint-order依 ADR-0009,字串退回比較採 Unicode 碼點順序——不做語系感知排序。
061concat-canonical-form依 ADR-0009,& 將運算元以正規字串形式字串化(布林大寫、整數不帶小數)。
062concat-empty-stringifies-to-empty依 ADR-0009,& 對空運算元貢獻空字串。
063compare-empty-vs-value依 ADR-0009 規則 1 與 2,兩個空運算元視為相等;其中一個為空時 = 為假。
064compare-unicode-minus-not-numeric含 Unicode 減號(U+2212)的字串不會被解析為數字;依 ADR-0009 落到正規字串退回比較。
065input-text-default-applied當宿主省略值時,_inputs 文字輸入的預設值會填入(ADR-0010)。
066input-text-host-supplied宿主提供的輸入值會流入儲存格、工作表名稱與輸出檔名樣式(ADR-0010)。
067input-missing-required-error必填的 _inputs 宣告(無預設值)若宿主省略,視為錯誤(ADR-0010)。
068input-select-host-suppliedselect 輸入接受位於宣告管線分隔選項中的宿主值(ADR-0010)。
069source-multi-declaration依 ADR-0012,__sources__ 工作表宣告額外的具名來源;對其的彙總會作用在其完整列集合上。
070source-aggregate-cross-source依 ADR-0012,對具名來源的 COUNT/MIN/MAX 作用在其完整列集合上。
071source-directive-active依 ADR-0012,@source SourceName 為資料區塊定範圍;其內 [Column] 解析至該來源。
072source-undeclared-error依 ADR-0012,@source 參照未在 __sources__ 宣告的來源是解析期錯誤。
073source-row-cross-error依 ADR-0012,列層級參照非作用中來源的欄位是錯誤。
074xlookup-basic依 ADR-0013,3-參數 XLOOKUP 對第一個 lookup-array 相符的列,回傳其 return-array 欄。
075xlookup-fallback依 ADR-0013,4-參數 XLOOKUP 在無相符列時回傳退回值。
076xlookup-no-match-error依 ADR-0013,無退回值的 3-參數 XLOOKUP 找不到相符列時回報錯誤。
077xlookup-source-mismatch-error依 ADR-0013,XLOOKUP 第 2 與第 3 個引數必須參照同一個來源。
078xlookup-bare-bracket-error依 ADR-0013,XLOOKUP 的第 2 / 第 3 個引數需為帶來源前綴的中括號參照。
079join-basic-inner依 ADR-0014,@join 將每筆主要列與第一個相符的被聯結列配對。
080join-no-match-dropped依 ADR-0014,@join 採內部聯結語意——沒有相符的主要列會被丟棄。
081join-undeclared-source-error依 ADR-0014,@join 參照未在 __sources__ 宣告的來源是解析期錯誤。
082join-bad-on-clause-error依 ADR-0014,@join 的 on 子句須同時參照被聯結來源與該區塊的主要來源。
083sort-stable-equal-keys依 ADR-0016,@sort 是穩定的——鍵值相同的列保留來源順序。
084sort-multi-stable-priority依 ADR-0016,多個 @sort 指示子套用時,首個為主鍵,後續作為次序鍵。
085file-group-first-seen-order依 ADR-0016,檔案群組依來源列的首次出現順序輸出。
086sheet-group-first-seen-order依 ADR-0016,檔案內的工作表群組依首次出現順序輸出。
087date-canonical-string-concat依 ADR-0017,日期在 & 中產生 YYYY-MM-DD(午夜)或 YYYY-MM-DDTHH:mm:ss。
088date-comparison-equality依 ADR-0017,日期值透過正規字串形式與字串篩選值比較。
089error-sentinel-empty依 ADR-0017,Excel 錯誤儲存格(#N/A#VALUE!、…)讀取時視為空值。
090percentage-numeric-flow依 ADR-0017,百分比格式儲存格以其底層數字流動(50% → 0.5)。

狀態

XTL 0.1 語料庫處於 啟動狀態。新增 fixture 時,SHOULD 只針對已在 spec/README.md 中明文敘述的行為,沿用 CommonMark 等標準專案的相同模式:散文定義規則,fixture 把規則變得可執行,實作則回報自己通過了哪些 fixture。

參考實作不會把自己的行為視為規範。當 fixture 與實作不一致時,依 spec/README.md 中的規格優先順序,更新實作或更新 fixture。

XTL 0.1 核心行為的 fixture 會避開實作自訂的擴充,例如 spec/language.md 最低表格之外的 TEXT() 格式。