xlsxrb 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +1 -1
- data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/ast/2.4/ast.rbs +73 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +4 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +16 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +96 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +4 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +68 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +249 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +4 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +47 -0
- data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +5 -0
- data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/csv/3.3/csv.rbs +3871 -0
- data/.gem_rbs_collection/csv/3.3/manifest.yaml +3 -0
- data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +48 -0
- data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/listen/3.9/listen.rbs +25 -0
- data/.gem_rbs_collection/listen/3.9/listener.rbs +24 -0
- data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/logger/1.7/formatter.rbs +45 -0
- data/.gem_rbs_collection/logger/1.7/log_device.rbs +100 -0
- data/.gem_rbs_collection/logger/1.7/logger.rbs +796 -0
- data/.gem_rbs_collection/logger/1.7/manifest.yaml +2 -0
- data/.gem_rbs_collection/logger/1.7/period.rbs +17 -0
- data/.gem_rbs_collection/logger/1.7/severity.rbs +34 -0
- data/.gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/nokogiri/1.11/nokogiri.rbs +2332 -0
- data/.gem_rbs_collection/nokogiri/1.11/patch.rbs +4 -0
- data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parallel/1.20/parallel.rbs +86 -0
- data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/parser/3.2/manifest.yaml +7 -0
- data/.gem_rbs_collection/parser/3.2/parser.rbs +194 -0
- data/.gem_rbs_collection/parser/3.2/polyfill.rbs +4 -0
- data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rainbow/3.0/global.rbs +7 -0
- data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +209 -0
- data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +5 -0
- data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rake/13.0/manifest.yaml +2 -0
- data/.gem_rbs_collection/rake/13.0/rake.rbs +39 -0
- data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +17 -0
- data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +208 -0
- data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +903 -0
- data/.gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml +9 -0
- data/.gem_rbs_collection/rubyzip/3.2/manifest.yaml +8 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs +42 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs +5 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/constants.rbs +47 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs +30 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs +9 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs +7 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs +19 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs +31 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs +18 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs +12 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs +11 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs +13 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry.rbs +95 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs +31 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/errors.rbs +58 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs +24 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs +17 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs +23 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs +22 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs +30 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs +20 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs +15 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs +26 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs +21 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/file.rbs +131 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs +14 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs +33 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs +21 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs +63 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs +55 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs +35 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs +7 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs +10 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs +22 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs +29 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs +17 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs +13 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs +10 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs +8 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs +6 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs +30 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs +10 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs +10 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs +5 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs +15 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip/version.rbs +3 -0
- data/.gem_rbs_collection/rubyzip/3.2/zip.rbs +40 -0
- data/CHANGELOG.md +42 -3
- data/README.md +130 -49
- data/Rakefile +23 -2
- data/Steepfile +17 -0
- data/benchmark.rb +324 -348
- data/docs/ARCHITECTURE.md +24 -0
- data/docs/DEVELOPMENT.md +58 -0
- data/docs/QUALITY_ASSURANCE.md +26 -0
- data/docs/visual/VisualGallery.md +893 -938
- data/docs/wasm/ruby.wasm +0 -0
- data/lib/xlsxrb/elements/cell.rb +113 -8
- data/lib/xlsxrb/elements/column.rb +2 -0
- data/lib/xlsxrb/elements/row.rb +52 -4
- data/lib/xlsxrb/elements/types.rb +6 -0
- data/lib/xlsxrb/elements/workbook.rb +29 -0
- data/lib/xlsxrb/elements/worksheet.rb +98 -1
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/ooxml/reader.rb +8 -6
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +106 -40
- data/lib/xlsxrb/ooxml/styles_parser.rb +2 -0
- data/lib/xlsxrb/ooxml/utils.rb +2 -0
- data/lib/xlsxrb/ooxml/workbook_parser.rb +6 -1
- data/lib/xlsxrb/ooxml/workbook_writer.rb +15 -4
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +156 -23
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +207 -152
- data/lib/xlsxrb/ooxml/writer.rb +217 -5
- data/lib/xlsxrb/ooxml/xml_builder.rb +18 -10
- data/lib/xlsxrb/ooxml/xml_parser.rb +2 -0
- data/lib/xlsxrb/ooxml/zip_generator.rb +5 -8
- data/lib/xlsxrb/ooxml/zip_reader.rb +179 -57
- data/lib/xlsxrb/ooxml/zip_writer.rb +65 -25
- data/lib/xlsxrb/ooxml.rb +3 -1
- data/lib/xlsxrb/style_builder.rb +284 -36
- data/lib/xlsxrb/version.rb +3 -1
- data/lib/xlsxrb.rb +1761 -275
- data/rbs_collection.lock.yaml +252 -0
- data/rbs_collection.yaml +19 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +30 -0
- data/sig/generated/xlsxrb/elements/column.rbs +30 -0
- data/sig/generated/xlsxrb/elements/row.rbs +32 -0
- data/sig/generated/xlsxrb/elements/types.rbs +74 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +25 -0
- data/sig/generated/xlsxrb/elements/worksheet.rbs +27 -0
- data/sig/generated/xlsxrb/elements.rbs +8 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +1412 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +21 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +44 -0
- data/sig/generated/xlsxrb/ooxml/utils.rbs +40 -0
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +46 -0
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +66 -0
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +67 -0
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +92 -0
- data/sig/generated/xlsxrb/ooxml/writer.rbs +880 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +45 -0
- data/sig/generated/xlsxrb/ooxml/xml_parser.rbs +30 -0
- data/sig/generated/xlsxrb/ooxml/zip_generator.rbs +38 -0
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +45 -0
- data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +45 -0
- data/sig/generated/xlsxrb/ooxml.rbs +23 -0
- data/sig/generated/xlsxrb/style_builder.rbs +250 -0
- data/sig/generated/xlsxrb/version.rbs +5 -0
- data/sig/generated/xlsxrb.rbs +1276 -0
- data/sig/rexml.rbs +4 -0
- metadata +145 -4
- data/measure_memory.rb +0 -42
- data/sig/xlsxrb.rbs +0 -23
data/docs/ARCHITECTURE.md
CHANGED
|
@@ -18,6 +18,30 @@ Xlsxrb uses **only** the Ruby standard library and Bundled Gems:
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Coding Policies
|
|
22
|
+
|
|
23
|
+
### 🚫 The `method_missing` Policy
|
|
24
|
+
As a strict rule, **we do not accept dynamic method definitions using `method_missing`** anywhere in the codebase. All user-facing API methods and internal delegations must be explicitly defined in the code. This ensures:
|
|
25
|
+
1. **Type Safety & Static Analysis**: RBS and Steep can completely validate arguments and structures.
|
|
26
|
+
2. **Developer Experience**: IDE autocompletion, jump-to-definition, and YARD documentation work perfectly.
|
|
27
|
+
3. **Traceability**: If a method exists, you can `grep` for it.
|
|
28
|
+
|
|
29
|
+
Even in cases where proxy patterns (e.g. `WorksheetProxy`) or OOXML builder mappings (e.g. `ChartBuilder`, `SeriesBuilder`) would traditionally benefit from dynamic delegation to avoid boilerplate, we explicitly generate and write out those delegations in the source code.
|
|
30
|
+
|
|
31
|
+
### 1. **`Xlsxrb` Module is the ONLY Entrypoint:**
|
|
32
|
+
The `Xlsxrb` module provides the top-level methods: `generate`, `build`, `read`, `foreach`, and `modify`. Users should **never** instantiate internal classes (like `Xlsxrb::Ooxml::WorkbookWriter`) directly.
|
|
33
|
+
|
|
34
|
+
2. **The `@api public` Contract (SemVer Guarantee):**
|
|
35
|
+
Any module, class, or method tagged with `# @api public` in its YARD documentation is guaranteed to follow Semantic Versioning.
|
|
36
|
+
- Patch versions (0.1.x -> 0.1.y) will not break these APIs.
|
|
37
|
+
- Minor versions (0.x.0 -> 0.y.0) will not break these APIs once 1.0.0 is released (during 0.x.x, it is a best-effort promise).
|
|
38
|
+
- Major versions (1.x -> 2.x) are the only time breaking changes to `@api public` components are permitted.
|
|
39
|
+
|
|
40
|
+
3. **Block-Yielded Objects are Public APIs:**
|
|
41
|
+
All builder objects yielded into blocks (e.g., `writer` in `Xlsxrb.generate { |writer| }`, `sheet` in `writer.sheet { |sheet| }`, `chart` in `sheet.chart { |chart| }`) are explicitly marked as `@api public`. Their exposed methods constitute the DSL and are strictly protected by the SemVer contract.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
21
45
|
## Directory Structure
|
|
22
46
|
|
|
23
47
|
```
|
data/docs/DEVELOPMENT.md
CHANGED
|
@@ -65,3 +65,61 @@ Omission is only acceptable when **all** of the following hold:
|
|
|
65
65
|
3. Unit tests and round-trip tests fully cover the new behaviour.
|
|
66
66
|
4. `rake test` passes with Open XML SDK validation included.
|
|
67
67
|
5. The commit message explicitly names the existing E2E scenario that provides coverage and states why a new scenario adds no value.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Development via Dev Container
|
|
72
|
+
|
|
73
|
+
The project is pre-configured with a Dev Container to simplify local environment setup (installing .NET, LibreOffice, ImageMagick, and Noto fonts).
|
|
74
|
+
|
|
75
|
+
### VS Code (GUI)
|
|
76
|
+
You can open this repository in VS Code and select **"Dev Containers: Reopen in Container"** from the Command Palette.
|
|
77
|
+
|
|
78
|
+
### Terminal (Devcontainer CLI)
|
|
79
|
+
If you prefer to use the terminal instead of VS Code, you can run the devcontainer using the official `@devcontainers/cli`:
|
|
80
|
+
|
|
81
|
+
1. Install the CLI on your host machine (if not already installed):
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @devcontainers/cli
|
|
84
|
+
```
|
|
85
|
+
2. Use the helper script `bin/devcontainer` to start and interact with the container:
|
|
86
|
+
- **Interactive shell** (Automatically shares your host's Git/AI tool configs as read-only):
|
|
87
|
+
```bash
|
|
88
|
+
bin/devcontainer
|
|
89
|
+
```
|
|
90
|
+
- **Run commands directly**:
|
|
91
|
+
```bash
|
|
92
|
+
bin/devcontainer rake test
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Customizing with Personal Overrides (e.g., Dotfiles, API Keys, Shell History)
|
|
96
|
+
|
|
97
|
+
The `bin/devcontainer` script dynamically parses a personal configuration patch and maps it to devcontainer CLI flags on startup. This is a workaround for a specification limit of devcontainer CLI's `--override-config` flag, which acts as a complete replacement of the configuration rather than a partial merge, wiping out base configurations like build settings.
|
|
98
|
+
|
|
99
|
+
To configure this, create a JSON (or JSONC) file at `${XDG_CONFIG_HOME:-~/.config}/devcontainer/override.jsonc` (or `override.json`) on your host machine.
|
|
100
|
+
|
|
101
|
+
**Example: Persisting histories, forwarding API keys, and Auto-installing Dotfiles**
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"mounts": [
|
|
105
|
+
// Volume for general persistent directories (e.g., Claude Code history in ~/.local/share/claude)
|
|
106
|
+
"type=volume,source=xlsxrb-local-share,target=/home/vscode/.local/share"
|
|
107
|
+
],
|
|
108
|
+
"containerEnv": {
|
|
109
|
+
// Explicitly forward API keys from your host shell to the container environment
|
|
110
|
+
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}",
|
|
111
|
+
"ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}",
|
|
112
|
+
"GEMINI_API_KEY": "${localEnv:GEMINI_API_KEY}"
|
|
113
|
+
},
|
|
114
|
+
"dotfiles": {
|
|
115
|
+
"repository": "https://github.com/<your-github-username>/dotfiles.git",
|
|
116
|
+
"targetPath": "~/dotfiles",
|
|
117
|
+
"installCommand": "install.sh"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
You can also use a custom file path by exporting the `DEVCONTAINER_OVERRIDE_CONFIG` environment variable in your host shell:
|
|
123
|
+
```bash
|
|
124
|
+
export DEVCONTAINER_OVERRIDE_CONFIG="/path/to/your/custom-override.json"
|
|
125
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Quality Assurance (QA) & Testing Architecture
|
|
2
|
+
|
|
3
|
+
`xlsxrb` is designed to be an enterprise-grade, highly reliable, and highly performant library for reading and writing Excel spreadsheets. To achieve and maintain this standard, we have implemented a comprehensive Quality Assurance matrix that covers everything from static code analysis and dynamic runtime validation to performance benchmarking and visual regression testing.
|
|
4
|
+
|
|
5
|
+
Below is an overview of the inspection mechanisms, when they run, the quality attributes they guarantee, and the specific bugs they prevent.
|
|
6
|
+
|
|
7
|
+
## QA Matrix
|
|
8
|
+
|
|
9
|
+
| Inspection Mechanism / Tool | Execution Command / Mechanism | Local | CI (PR/Push) | Scheduled (Weekly) | Target Quality Attribute | Validation Method | Prevented Bugs / Issues |
|
|
10
|
+
| :--- | :--- | :---: | :---: | :---: | :--- | :--- | :--- |
|
|
11
|
+
| **RuboCop** | `rake rubocop` | ⭕ | ⭕ | - | Readability / Maintainability | Static Analysis (Syntax/Linting) | Overly complex methods, non-standard syntax, unused variables. |
|
|
12
|
+
| **Steep & RBS** | `rake typecheck` | ⭕ | ⭕ | - | Type Safety (Static) | Static Analysis (Type Check) | `NoMethodError`, passing incorrect arguments, method typo bugs. |
|
|
13
|
+
| **Bundler Audit** | `rake audit` | - | ⭕ | - | Security | Dependency Scanning | Inclusion of external gems with known vulnerabilities (CVEs). |
|
|
14
|
+
| **Dependabot** | `.github/dependabot.yml` | - | - | ⭕ | Currency / Maintenance | Repository Monitoring | Outdated dependencies or CI actions. |
|
|
15
|
+
| **Unit & Contract Tests** | `rake test:unit test:contract` | ⭕ | ⭕ | - | Accuracy / Functional Reqs | Dynamic Analysis (Assertions) | Method specification violations, unexpected return values, edge-case failures. |
|
|
16
|
+
| **Runtime Type Validation (RBS::Test)** | `rake test:rbs` | △ (Opt-in) | ⭕ | - | Type Safety (Dynamic) | Dynamic Analysis (Runtime Hooks) | Type errors slipping past static checks, divergence between RBS docs and implementation. |
|
|
17
|
+
| **Property-Based Testing (PBT)** | Included in `rake test:unit` | ⭕ | ⭕ | - | Robustness / Exhaustiveness | Automated Random Generation | Crashes caused by "unexpected inputs" (e.g., empty strings, huge numbers, special symbols like `=`). |
|
|
18
|
+
|
|
19
|
+
| **Security Validation (DoS Protection)** | Included in `rake test:unit` | ⭕ | ⭕ | - | Availability / Safety | Dynamic Analysis (Malicious Input) | Memory/disk exhaustion from ZIP bombs, infinite parsing loops from malformed files. |
|
|
20
|
+
| **Concurrency Validation (Thread/Ractor)** | Included in `rake test:unit` | ⭕ | ⭕ | - | Thread Safety | Dynamic Analysis (Parallel Execution) | Global variable pollution, data mixing during concurrent request processing. |
|
|
21
|
+
| **XSD Schema Validation** | Included in `rake test:unit` | ⭕ | ⭕ | - | Compatibility / Compliance | Structural Validation | "We found a problem with some content in it" errors when opening in Excel. |
|
|
22
|
+
| **E2E Interoperability Tests** | `rake test:e2e` | △ (Opt-in) | ⭕ | - | Compatibility (Real-world) | 3rd-party SDK Execution | Structural defects so severe that the official .NET SDK cannot read them. |
|
|
23
|
+
| **Load / Stress Testing** | Action: `benchmark.yml` | - | ⭕ | - | Performance / Stability | Massive Data Generation (e.g., 10k+ rows) | Out of Memory (OOM) crashes or extreme delays when processing large datasets. |
|
|
24
|
+
| **Memory & Speed Benchmark** | Action: `benchmark.yml` | - | ⭕ | - | Performance | Continuous Profiling | Memory leaks, severe performance degradation due to inefficient loop additions. |
|
|
25
|
+
| **Visual Regression Testing (VRT)** | `rake test:visual` | - | ⭕ | - | Visual Accuracy (UI/UX) | Headless Rendering / Pixel Diff | Visual bugs like "cell background colors dropping" or "chart layouts breaking" after code changes. |
|
|
26
|
+
|