@yeyuan98/opencode-bioresearcher-plugin 1.6.8 → 1.7.0
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.
- package/dist/skills/bioresearcher-tests/SKILL.md +46 -4
- package/dist/skills/bioresearcher-tests/test_cases/table_tests.md +347 -9
- package/dist/skills/bioresearcher-tests/test_runner.py +36 -1
- package/dist/tools/table/index.d.ts +35 -7
- package/dist/tools/table/tools.d.ts +36 -8
- package/dist/tools/table/tools.js +269 -117
- package/dist/tools/table/utils.d.ts +7 -1
- package/dist/tools/table/utils.js +56 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -38,7 +38,7 @@ Comprehensive test suite for bioresearcher plugin tools and skills.
|
|
|
38
38
|
| Category | Tools | Status |
|
|
39
39
|
|----------|-------|--------|
|
|
40
40
|
| Parser | `parse_pubmed_articleSet`, `parse_obo_file` | Full tests |
|
|
41
|
-
| Table | All 13 `table*` tools | Full tests + negative tests |
|
|
41
|
+
| Table | All 13 `table*` tools | Full tests + negative tests + hardening tests + large table tests |
|
|
42
42
|
| JSON | `jsonExtract`, `jsonValidate`, `jsonInfer` | Full tests |
|
|
43
43
|
| Misc | `blockingTimer`, `calculator` | Full tests |
|
|
44
44
|
| Skills | `demo-skill` | Full execution |
|
|
@@ -97,15 +97,16 @@ Record pass/fail for each test.
|
|
|
97
97
|
|
|
98
98
|
### Step 4: Run Table Tests
|
|
99
99
|
|
|
100
|
-
Execute tests from `<skill_path>/test_cases/table_tests.md
|
|
100
|
+
Execute tests from `<skill_path>/test_cases/table_tests.md` in order:
|
|
101
101
|
|
|
102
|
+
**Basic functionality (13 tests):**
|
|
102
103
|
1. `tableListSheets` - List sheets in sample Excel
|
|
103
104
|
2. `tableGetSheetPreview` - Get first 6 rows
|
|
104
105
|
3. `tableGetHeaders` - Get column headers
|
|
105
106
|
4. `tableGetCell` - Get specific cell value
|
|
106
107
|
5. `tableGetRange` - Get A1:C3 range
|
|
107
|
-
6. `tableFilterRows` - Filter by Age > 25
|
|
108
|
-
7. `tableSearch` - Search for "
|
|
108
|
+
6. `tableFilterRows` - Filter by Age > 25 (verify new `total_matches_found` + `returned_count` fields)
|
|
109
|
+
7. `tableSearch` - Search for "Active"
|
|
109
110
|
8. `tableSummarize` - Get stats for numeric columns
|
|
110
111
|
9. `tableGroupBy` - Group by Category
|
|
111
112
|
10. `tableCreateFile` - Create new Excel file
|
|
@@ -113,6 +114,47 @@ Execute tests from `<skill_path>/test_cases/table_tests.md`:
|
|
|
113
114
|
12. `tableUpdateCell` - Update cell A1
|
|
114
115
|
13. `tablePivotSummary` - Create pivot table
|
|
115
116
|
|
|
117
|
+
**Error / negative tests (5 tests):**
|
|
118
|
+
14. Nonexistent File - error handling
|
|
119
|
+
15. Invalid Cell Address - descriptive error message
|
|
120
|
+
16. Invalid Filter Operator - error handling
|
|
121
|
+
17. Nonexistent Column - graceful handling
|
|
122
|
+
18. Out of Bounds Range - empty data
|
|
123
|
+
|
|
124
|
+
**Phase 2 correctness tests (10 tests):**
|
|
125
|
+
19. Pivot Avg Numeric-Only Denominator - Setup (create test file)
|
|
126
|
+
20. Pivot Avg Numeric-Only Denominator - Verify (avg = 20.0, not 10.0)
|
|
127
|
+
21. Pivot Max Handles Negative Values - Setup (create test file)
|
|
128
|
+
22. Pivot Max Handles Negative Values - Verify (max = 3, not 0)
|
|
129
|
+
23. CreateFile Overwrite Guard - rejects without `overwrite: true`
|
|
130
|
+
24. CreateFile Overwrite Succeeds - works with `overwrite: true`
|
|
131
|
+
25. FilterRows New Response Fields - `total_matches_found` + `returned_count`
|
|
132
|
+
26. UpdateCell Invalid Address Path Traversal - rejects `../../etc/passwd`
|
|
133
|
+
27. UpdateCell Null Value - accepts null without error
|
|
134
|
+
28. CreateFile Invalid Data Schema - rejects non-array data
|
|
135
|
+
|
|
136
|
+
**Hardening feature tests (8 tests):**
|
|
137
|
+
29. Force Parameter - Filter Rows (regression check)
|
|
138
|
+
30. Force Parameter - Summarize (regression check)
|
|
139
|
+
31. File Size Limit - Reject Large File (generate 55MB via `dd`)
|
|
140
|
+
32. File Size Limit - Bypass With Force (same file, `force: true`)
|
|
141
|
+
33. Range Limit - Reject Oversized Range (`A1:ZZZ1000`)
|
|
142
|
+
34. Range Limit - Bypass With Force
|
|
143
|
+
35. Error Sanitization - No Resolved Paths (no `/home/`, `/root/`, `/tmp/`)
|
|
144
|
+
36. Error Sanitization - Uses Original Path
|
|
145
|
+
|
|
146
|
+
**Large table tests (8 tests):**
|
|
147
|
+
37. Large Table - Generate Via Python (`openpyxl` row duplication, 150K+ rows)
|
|
148
|
+
38. Large Table - Filter Rows Truncation (verify `truncated: true`)
|
|
149
|
+
39. Large Table - Filter Rows With Force (no truncation)
|
|
150
|
+
40. Large Table - Summarize Truncation
|
|
151
|
+
41. Large Table - Search Truncation
|
|
152
|
+
42. Large Table - GroupBy Truncation
|
|
153
|
+
43. Large Table - PivotSummary Truncation
|
|
154
|
+
44. Large Table - Cleanup (remove all generated test files)
|
|
155
|
+
|
|
156
|
+
> **Important:** The large table tests (35-42) require `openpyxl` to be installed. If not available, install with `pip install openpyxl`. The large table is generated during the test and cleaned up afterward - no large files are shipped with the plugin.
|
|
157
|
+
|
|
116
158
|
Record pass/fail for each test.
|
|
117
159
|
|
|
118
160
|
### Step 5: Run JSON Tests
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Table Tool Tests
|
|
2
2
|
|
|
3
|
+
## Basic Functionality Tests
|
|
4
|
+
|
|
3
5
|
## Test: List Sheets
|
|
4
6
|
- Tool: tableListSheets
|
|
5
7
|
- Input:
|
|
@@ -64,8 +66,9 @@
|
|
|
64
66
|
```
|
|
65
67
|
- Validators:
|
|
66
68
|
- has matched_rows
|
|
67
|
-
- has
|
|
68
|
-
-
|
|
69
|
+
- has total_matches_found
|
|
70
|
+
- has returned_count
|
|
71
|
+
- Expected: Filtered rows where Age > 25 with new response fields
|
|
69
72
|
|
|
70
73
|
## Test: Search
|
|
71
74
|
- Tool: tableSearch
|
|
@@ -75,8 +78,9 @@
|
|
|
75
78
|
```
|
|
76
79
|
- Validators:
|
|
77
80
|
- has results array
|
|
78
|
-
- has
|
|
79
|
-
-
|
|
81
|
+
- has total_matches_found
|
|
82
|
+
- has returned_count
|
|
83
|
+
- Expected: Cells containing "Active" with new response fields
|
|
80
84
|
|
|
81
85
|
## Test: Summarize
|
|
82
86
|
- Tool: tableSummarize
|
|
@@ -143,6 +147,8 @@
|
|
|
143
147
|
- has columns array
|
|
144
148
|
- Expected: Pivot table with Category rows, Status columns, Score sums
|
|
145
149
|
|
|
150
|
+
## Error / Negative Tests
|
|
151
|
+
|
|
146
152
|
## Test: Nonexistent File
|
|
147
153
|
- Tool: tableListSheets
|
|
148
154
|
- Input:
|
|
@@ -161,17 +167,20 @@
|
|
|
161
167
|
```
|
|
162
168
|
- Validators:
|
|
163
169
|
- contains_string("Error")
|
|
164
|
-
-
|
|
170
|
+
- contains_string("Invalid cell address")
|
|
171
|
+
- Expected: Error response with descriptive message
|
|
165
172
|
|
|
166
|
-
## Test:
|
|
173
|
+
## Test: No Match Filter
|
|
167
174
|
- Tool: tableFilterRows
|
|
168
175
|
- Input:
|
|
169
176
|
```json
|
|
170
|
-
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "column": "Age", "operator": "
|
|
177
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "column": "Age", "operator": ">", "value": 999999, "max_results": 100}
|
|
171
178
|
```
|
|
172
179
|
- Validators:
|
|
173
|
-
-
|
|
174
|
-
-
|
|
180
|
+
- has total_matches_found
|
|
181
|
+
- has returned_count
|
|
182
|
+
- has matched_rows
|
|
183
|
+
- Expected: Zero matches returned (valid query with no matching rows)
|
|
175
184
|
|
|
176
185
|
## Test: Nonexistent Column
|
|
177
186
|
- Tool: tableSummarize
|
|
@@ -192,3 +201,332 @@
|
|
|
192
201
|
- Validators:
|
|
193
202
|
- has data array
|
|
194
203
|
- Expected: Empty data array (out of bounds handled)
|
|
204
|
+
|
|
205
|
+
## Phase 2 Correctness Tests
|
|
206
|
+
|
|
207
|
+
## Test: Pivot Avg Numeric-Only Denominator - Setup
|
|
208
|
+
- Tool: tableCreateFile
|
|
209
|
+
- Input:
|
|
210
|
+
```json
|
|
211
|
+
{"file_path": ".bioresearcher-tests/workspace/pivot_avg_test.xlsx", "sheet_name": "Sheet1", "data": [{"Group": "A", "Type": "X", "Val": 10}, {"Group": "A", "Type": "X", "Val": ""}, {"Group": "A", "Type": "X", "Val": 30}, {"Group": "B", "Type": "Y", "Val": 20}, {"Group": "B", "Type": "Y", "Val": 40}]}
|
|
212
|
+
```
|
|
213
|
+
- Validators:
|
|
214
|
+
- success_is_true
|
|
215
|
+
- Expected: File created for pivot avg test
|
|
216
|
+
|
|
217
|
+
## Test: Pivot Avg Numeric-Only Denominator - Verify
|
|
218
|
+
- Tool: tablePivotSummary
|
|
219
|
+
- Prerequisite: Test "Pivot Avg Numeric-Only Denominator - Setup" must pass first
|
|
220
|
+
- Input:
|
|
221
|
+
```json
|
|
222
|
+
{"file_path": ".bioresearcher-tests/workspace/pivot_avg_test.xlsx", "row_field": "Group", "col_field": "Type", "value_field": "Val", "agg": "avg"}
|
|
223
|
+
```
|
|
224
|
+
- Validators:
|
|
225
|
+
- has pivot object
|
|
226
|
+
- Expected: Group A avg = 20.0 (10+30 divided by 2, not 3)
|
|
227
|
+
|
|
228
|
+
## Test: Pivot Max Handles Negative Values - Setup
|
|
229
|
+
- Tool: tableCreateFile
|
|
230
|
+
- Input:
|
|
231
|
+
```json
|
|
232
|
+
{"file_path": ".bioresearcher-tests/workspace/pivot_neg_test.xlsx", "sheet_name": "Sheet1", "data": [{"Group": "A", "Val": -5}, {"Group": "A", "Val": -10}, {"Group": "A", "Val": 3}]}
|
|
233
|
+
```
|
|
234
|
+
- Validators:
|
|
235
|
+
- success_is_true
|
|
236
|
+
- Expected: File created for pivot neg test
|
|
237
|
+
|
|
238
|
+
## Test: Pivot Max Handles Negative Values - Verify
|
|
239
|
+
- Tool: tablePivotSummary
|
|
240
|
+
- Prerequisite: Test "Pivot Max Handles Negative Values - Setup" must pass first
|
|
241
|
+
- Input:
|
|
242
|
+
```json
|
|
243
|
+
{"file_path": ".bioresearcher-tests/workspace/pivot_neg_test.xlsx", "row_field": "Group", "col_field": "Group", "value_field": "Val", "agg": "max"}
|
|
244
|
+
```
|
|
245
|
+
- Validators:
|
|
246
|
+
- has pivot object
|
|
247
|
+
- Expected: Max is 3, not 0
|
|
248
|
+
|
|
249
|
+
## Test: CreateFile Overwrite Guard
|
|
250
|
+
- Prerequisite: Test "Create File" must pass first (output_created.xlsx exists)
|
|
251
|
+
- Tool: tableCreateFile
|
|
252
|
+
- Input:
|
|
253
|
+
```json
|
|
254
|
+
{"file_path": ".bioresearcher-tests/workspace/output_created.xlsx", "sheet_name": "Sheet1", "data": [{"Name": "Override"}]}
|
|
255
|
+
```
|
|
256
|
+
- Validators:
|
|
257
|
+
- contains_string("already exists")
|
|
258
|
+
- contains_string("overwrite: true")
|
|
259
|
+
- Expected: Error because file exists and overwrite is not set
|
|
260
|
+
|
|
261
|
+
## Test: CreateFile Overwrite Succeeds
|
|
262
|
+
- Prerequisite: Test "CreateFile Overwrite Guard" must run first
|
|
263
|
+
- Tool: tableCreateFile
|
|
264
|
+
- Input:
|
|
265
|
+
```json
|
|
266
|
+
{"file_path": ".bioresearcher-tests/workspace/output_created.xlsx", "sheet_name": "Sheet1", "data": [{"Name": "Overwritten"}], "overwrite": true}
|
|
267
|
+
```
|
|
268
|
+
- Validators:
|
|
269
|
+
- success_is_true
|
|
270
|
+
- rows_created === 1
|
|
271
|
+
- Expected: File overwritten successfully
|
|
272
|
+
|
|
273
|
+
## Test: FilterRows New Response Fields
|
|
274
|
+
- Tool: tableFilterRows
|
|
275
|
+
- Input:
|
|
276
|
+
```json
|
|
277
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "column": "Age", "operator": ">=", "value": 0, "max_results": 5}
|
|
278
|
+
```
|
|
279
|
+
- Validators:
|
|
280
|
+
- has total_matches_found
|
|
281
|
+
- has returned_count
|
|
282
|
+
- has matched_rows
|
|
283
|
+
- Expected: Response includes total_matches_found and returned_count (replaces old total_matches)
|
|
284
|
+
|
|
285
|
+
## Test: UpdateCell Invalid Address Path Traversal
|
|
286
|
+
- Tool: tableUpdateCell
|
|
287
|
+
- Input:
|
|
288
|
+
```json
|
|
289
|
+
{"file_path": ".bioresearcher-tests/workspace/output_created.xlsx", "cell_address": "../../etc/passwd", "value": "test"}
|
|
290
|
+
```
|
|
291
|
+
- Validators:
|
|
292
|
+
- contains_string("Error")
|
|
293
|
+
- contains_string("Invalid cell address")
|
|
294
|
+
- Expected: Error response rejecting path traversal in cell address
|
|
295
|
+
|
|
296
|
+
## Test: UpdateCell Null Value
|
|
297
|
+
- Prerequisite: Test "CreateFile Overwrite Succeeds" must pass first
|
|
298
|
+
- Tool: tableUpdateCell
|
|
299
|
+
- Input:
|
|
300
|
+
```json
|
|
301
|
+
{"file_path": ".bioresearcher-tests/workspace/output_created.xlsx", "cell_address": "B1", "value": null}
|
|
302
|
+
```
|
|
303
|
+
- Validators:
|
|
304
|
+
- success_is_true
|
|
305
|
+
- Expected: Cell updated with null value without error
|
|
306
|
+
|
|
307
|
+
## Test: CreateFile Invalid Data Schema
|
|
308
|
+
- Tool: tableCreateFile
|
|
309
|
+
- Input:
|
|
310
|
+
```json
|
|
311
|
+
{"file_path": ".bioresearcher-tests/workspace/invalid_data.xlsx", "sheet_name": "Sheet1", "data": "not an array"}
|
|
312
|
+
```
|
|
313
|
+
- Validators:
|
|
314
|
+
- contains_string("Error")
|
|
315
|
+
- contains_string("must be an array")
|
|
316
|
+
- Expected: Error because data is a string, not an array
|
|
317
|
+
|
|
318
|
+
## Hardening Feature Tests
|
|
319
|
+
|
|
320
|
+
## Test: Force Parameter - Filter Rows
|
|
321
|
+
- Tool: tableFilterRows
|
|
322
|
+
- Input:
|
|
323
|
+
```json
|
|
324
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "column": "Age", "operator": ">", "value": 25, "max_results": 100, "force": true}
|
|
325
|
+
```
|
|
326
|
+
- Validators:
|
|
327
|
+
- has matched_rows
|
|
328
|
+
- has total_matches_found
|
|
329
|
+
- has returned_count
|
|
330
|
+
- Expected: Same results as Filter Rows without force (regression check)
|
|
331
|
+
|
|
332
|
+
## Test: Force Parameter - Summarize
|
|
333
|
+
- Tool: tableSummarize
|
|
334
|
+
- Input:
|
|
335
|
+
```json
|
|
336
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "columns": ["Age", "Score"], "force": true}
|
|
337
|
+
```
|
|
338
|
+
- Validators:
|
|
339
|
+
- has summaries object
|
|
340
|
+
- Expected: Same summaries as Summarize without force (regression check)
|
|
341
|
+
|
|
342
|
+
## Test: File Size Limit - Reject Large File
|
|
343
|
+
- Setup: Run the following Bash command to create a 55MB dummy file:
|
|
344
|
+
```bash
|
|
345
|
+
dd if=/dev/urandom of=.bioresearcher-tests/workspace/large_dummy.xlsx bs=1M count=55 2>/dev/null && echo "Created large file"
|
|
346
|
+
```
|
|
347
|
+
- Tool: tableListSheets
|
|
348
|
+
- Input:
|
|
349
|
+
```json
|
|
350
|
+
{"file_path": ".bioresearcher-tests/workspace/large_dummy.xlsx"}
|
|
351
|
+
```
|
|
352
|
+
- Validators:
|
|
353
|
+
- contains_string("Error")
|
|
354
|
+
- contains_string("exceeding")
|
|
355
|
+
- contains_string("force: true")
|
|
356
|
+
- Expected: Error rejecting file over 50MB limit with guidance to use force
|
|
357
|
+
|
|
358
|
+
## Test: File Size Limit - Bypass With Force
|
|
359
|
+
- Prerequisite: Test "File Size Limit - Reject Large File" must run first (large_dummy.xlsx exists)
|
|
360
|
+
- Tool: tableListSheets
|
|
361
|
+
- Input:
|
|
362
|
+
```json
|
|
363
|
+
{"file_path": ".bioresearcher-tests/workspace/large_dummy.xlsx", "force": true}
|
|
364
|
+
```
|
|
365
|
+
- Validators:
|
|
366
|
+
- has sheets array
|
|
367
|
+
- Expected: Size check bypassed with force: true; tool processed the file (parser may return partial results for corrupt data)
|
|
368
|
+
- Cleanup: Run `rm .bioresearcher-tests/workspace/large_dummy.xlsx`
|
|
369
|
+
|
|
370
|
+
## Test: Range Limit - Reject Oversized Range
|
|
371
|
+
- Tool: tableGetRange
|
|
372
|
+
- Input:
|
|
373
|
+
```json
|
|
374
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "range": "A1:ZZZ1000"}
|
|
375
|
+
```
|
|
376
|
+
- Validators:
|
|
377
|
+
- contains_string("Error")
|
|
378
|
+
- contains_string("exceeds")
|
|
379
|
+
- contains_string("force: true")
|
|
380
|
+
- Expected: Error rejecting range exceeding 50K cell limit
|
|
381
|
+
|
|
382
|
+
## Test: Range Limit - Bypass With Force
|
|
383
|
+
- Tool: tableGetRange
|
|
384
|
+
- Input:
|
|
385
|
+
```json
|
|
386
|
+
{"file_path": ".bioresearcher-tests/workspace/table_sample.xlsx", "range": "A1:ZZZ1000", "force": true}
|
|
387
|
+
```
|
|
388
|
+
- Validators:
|
|
389
|
+
- has data array
|
|
390
|
+
- Expected: Data array returned (mostly empty cells, but range limit bypassed)
|
|
391
|
+
|
|
392
|
+
## Test: Error Sanitization - No Resolved Paths
|
|
393
|
+
- Tool: tableGetCell
|
|
394
|
+
- Input:
|
|
395
|
+
```json
|
|
396
|
+
{"file_path": ".bioresearcher-tests/workspace/nonexistent_file.xlsx", "cell_address": "A1"}
|
|
397
|
+
```
|
|
398
|
+
- Validators:
|
|
399
|
+
- contains_string("Error")
|
|
400
|
+
- not contains_string("/home/")
|
|
401
|
+
- not contains_string("/root/")
|
|
402
|
+
- not contains_string("/tmp/")
|
|
403
|
+
- Expected: Error message does not leak absolute filesystem paths
|
|
404
|
+
|
|
405
|
+
## Test: Error Sanitization - Uses Original Path
|
|
406
|
+
- Tool: tableListSheets
|
|
407
|
+
- Input:
|
|
408
|
+
```json
|
|
409
|
+
{"file_path": ".bioresearcher-tests/workspace/nonexistent_file.xlsx"}
|
|
410
|
+
```
|
|
411
|
+
- Validators:
|
|
412
|
+
- contains_string("Error")
|
|
413
|
+
- contains_string(".bioresearcher-tests/workspace/nonexistent_file.xlsx")
|
|
414
|
+
- Expected: Error message references the original user-provided file path
|
|
415
|
+
|
|
416
|
+
## Large Table Tests
|
|
417
|
+
|
|
418
|
+
## Test: Large Table - Generate Via Python
|
|
419
|
+
- Setup: Run the following Python command to generate a table with 150K+ rows by duplicating the sample data:
|
|
420
|
+
```bash
|
|
421
|
+
pip install openpyxl -q 2>/dev/null; python3 -c "
|
|
422
|
+
import openpyxl
|
|
423
|
+
wb = openpyxl.load_workbook('.bioresearcher-tests/workspace/table_sample.xlsx')
|
|
424
|
+
ws = wb.active
|
|
425
|
+
rows = list(ws.iter_rows(values_only=True))
|
|
426
|
+
data_rows = rows[1:]
|
|
427
|
+
if not data_rows:
|
|
428
|
+
print('ERROR: no data rows found')
|
|
429
|
+
else:
|
|
430
|
+
target = 150000
|
|
431
|
+
for i in range(target // len(data_rows)):
|
|
432
|
+
for row in data_rows:
|
|
433
|
+
ws.append(row)
|
|
434
|
+
wb.save('.bioresearcher-tests/workspace/large_table.xlsx')
|
|
435
|
+
print(f'Created table with {ws.max_row} rows')
|
|
436
|
+
"
|
|
437
|
+
```
|
|
438
|
+
- Validators:
|
|
439
|
+
- contains_string("Created table with")
|
|
440
|
+
- Expected: large_table.xlsx created with 150K+ rows
|
|
441
|
+
|
|
442
|
+
## Test: Large Table - Filter Rows Truncation
|
|
443
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
444
|
+
- Tool: tableFilterRows
|
|
445
|
+
- Input:
|
|
446
|
+
```json
|
|
447
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "column": "Age", "operator": ">", "value": 0, "max_results": 50}
|
|
448
|
+
```
|
|
449
|
+
- Validators:
|
|
450
|
+
- has matched_rows
|
|
451
|
+
- has total_matches_found
|
|
452
|
+
- has returned_count
|
|
453
|
+
- truncated === true
|
|
454
|
+
- contains_string("Set force: true")
|
|
455
|
+
- Expected: Results truncated at row cap with guidance message
|
|
456
|
+
|
|
457
|
+
## Test: Large Table - Filter Rows With Force
|
|
458
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
459
|
+
- Tool: tableFilterRows
|
|
460
|
+
- Input:
|
|
461
|
+
```json
|
|
462
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "column": "Age", "operator": ">", "value": 0, "max_results": 50, "force": true}
|
|
463
|
+
```
|
|
464
|
+
- Validators:
|
|
465
|
+
- has matched_rows
|
|
466
|
+
- has total_matches_found
|
|
467
|
+
- has returned_count
|
|
468
|
+
- Expected: All rows processed, no truncation field
|
|
469
|
+
|
|
470
|
+
## Test: Large Table - Summarize Truncation
|
|
471
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
472
|
+
- Tool: tableSummarize
|
|
473
|
+
- Input:
|
|
474
|
+
```json
|
|
475
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "columns": ["Age"]}
|
|
476
|
+
```
|
|
477
|
+
- Validators:
|
|
478
|
+
- has summaries object
|
|
479
|
+
- truncated === true
|
|
480
|
+
- has processed_rows
|
|
481
|
+
- contains_string("Set force: true")
|
|
482
|
+
- Expected: Summary computed on capped rows with truncation notice
|
|
483
|
+
|
|
484
|
+
## Test: Large Table - Search Truncation
|
|
485
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
486
|
+
- Tool: tableSearch
|
|
487
|
+
- Input:
|
|
488
|
+
```json
|
|
489
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "search_term": "Active", "max_results": 10}
|
|
490
|
+
```
|
|
491
|
+
- Validators:
|
|
492
|
+
- has results array
|
|
493
|
+
- has total_matches_found
|
|
494
|
+
- has returned_count
|
|
495
|
+
- truncated === true
|
|
496
|
+
- has rows_scanned
|
|
497
|
+
- Expected: Search scanned up to 100K rows, counted all matches, returned limited results
|
|
498
|
+
|
|
499
|
+
## Test: Large Table - GroupBy Truncation
|
|
500
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
501
|
+
- Tool: tableGroupBy
|
|
502
|
+
- Input:
|
|
503
|
+
```json
|
|
504
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "group_column": "Category", "agg_column": "Score", "agg_type": "avg"}
|
|
505
|
+
```
|
|
506
|
+
- Validators:
|
|
507
|
+
- has groups object
|
|
508
|
+
- truncated === true
|
|
509
|
+
- has processed_rows
|
|
510
|
+
- Expected: GroupBy truncated at row cap
|
|
511
|
+
|
|
512
|
+
## Test: Large Table - PivotSummary Truncation
|
|
513
|
+
- Prerequisite: Test "Large Table - Generate Via Python" must pass first
|
|
514
|
+
- Tool: tablePivotSummary
|
|
515
|
+
- Input:
|
|
516
|
+
```json
|
|
517
|
+
{"file_path": ".bioresearcher-tests/workspace/large_table.xlsx", "row_field": "Category", "col_field": "Status", "value_field": "Score", "agg": "sum"}
|
|
518
|
+
```
|
|
519
|
+
- Validators:
|
|
520
|
+
- has pivot object
|
|
521
|
+
- truncated === true
|
|
522
|
+
- has processed_rows
|
|
523
|
+
- Expected: Pivot truncated at row cap
|
|
524
|
+
|
|
525
|
+
## Test: Large Table - Cleanup
|
|
526
|
+
- Setup: Run the following Bash command to remove the large table:
|
|
527
|
+
```bash
|
|
528
|
+
rm -f .bioresearcher-tests/workspace/large_table.xlsx .bioresearcher-tests/workspace/large_dummy.xlsx .bioresearcher-tests/workspace/pivot_avg_test.xlsx .bioresearcher-tests/workspace/pivot_neg_test.xlsx .bioresearcher-tests/workspace/invalid_data.xlsx .bioresearcher-tests/workspace/output_created.xlsx && echo "Cleanup done"
|
|
529
|
+
```
|
|
530
|
+
- Validators:
|
|
531
|
+
- contains_string("Cleanup done")
|
|
532
|
+
- Expected: All generated test files removed
|
|
@@ -376,9 +376,17 @@ def validate_result(result: Any, validators: list[str]) -> tuple[bool, list[dict
|
|
|
376
376
|
detail = f"has matched_rows: {passed}"
|
|
377
377
|
|
|
378
378
|
elif validator == "has total_matches":
|
|
379
|
-
passed = "total_matches" in result_obj
|
|
379
|
+
passed = "total_matches_found" in result_obj or "total_matches" in result_obj
|
|
380
380
|
detail = f"has total_matches: {passed}"
|
|
381
381
|
|
|
382
|
+
elif validator == "has total_matches_found":
|
|
383
|
+
passed = "total_matches_found" in result_obj
|
|
384
|
+
detail = f"has total_matches_found: {passed}"
|
|
385
|
+
|
|
386
|
+
elif validator == "has returned_count":
|
|
387
|
+
passed = "returned_count" in result_obj
|
|
388
|
+
detail = f"has returned_count: {passed}"
|
|
389
|
+
|
|
382
390
|
elif validator == "has results array":
|
|
383
391
|
passed = "results" in result_obj and isinstance(result_obj["results"], list)
|
|
384
392
|
detail = f"has results: {passed}"
|
|
@@ -405,10 +413,37 @@ def validate_result(result: Any, validators: list[str]) -> tuple[bool, list[dict
|
|
|
405
413
|
passed = "columns" in result_obj and isinstance(result_obj["columns"], list)
|
|
406
414
|
detail = f"has columns: {passed}"
|
|
407
415
|
|
|
416
|
+
elif validator == "has truncated":
|
|
417
|
+
passed = "truncated" in result_obj
|
|
418
|
+
detail = f"has truncated: {passed}"
|
|
419
|
+
|
|
420
|
+
elif validator == "has processed_rows":
|
|
421
|
+
passed = "processed_rows" in result_obj
|
|
422
|
+
detail = f"has processed_rows: {passed}"
|
|
423
|
+
|
|
424
|
+
elif validator == "has rows_scanned":
|
|
425
|
+
passed = "rows_scanned" in result_obj
|
|
426
|
+
detail = f"has rows_scanned: {passed}"
|
|
427
|
+
|
|
428
|
+
elif validator == "truncated === true":
|
|
429
|
+
passed = result_obj.get("truncated") is True
|
|
430
|
+
detail = f"truncated={result_obj.get('truncated')}"
|
|
431
|
+
|
|
432
|
+
elif validator.startswith("not contains_string"):
|
|
433
|
+
match = re.search(r'"(.+?)"', validator)
|
|
434
|
+
if match:
|
|
435
|
+
substr = match.group(1)
|
|
436
|
+
passed = substr.lower() not in result_str.lower()
|
|
437
|
+
detail = f"does NOT contain '{substr}': {passed}"
|
|
438
|
+
|
|
408
439
|
elif validator == "rows_appended === 1":
|
|
409
440
|
passed = result_obj.get("rows_appended") == 1
|
|
410
441
|
detail = f"rows_appended={result_obj.get('rows_appended')}"
|
|
411
442
|
|
|
443
|
+
elif validator == "rows_created === 1":
|
|
444
|
+
passed = result_obj.get("rows_created") == 1
|
|
445
|
+
detail = f"rows_created={result_obj.get('rows_created')}"
|
|
446
|
+
|
|
412
447
|
elif validator == "rows_created === 2":
|
|
413
448
|
passed = result_obj.get("rows_created") == 2
|
|
414
449
|
detail = f"rows_created={result_obj.get('rows_created')}"
|