test: finops formatting — formatBytes and truncateQuery edge cases#390
test: finops formatting — formatBytes and truncateQuery edge cases#390anandgupta42 wants to merge 3 commits intomainfrom
Conversation
Documents 5 confirmed bugs in finops-formatting.ts that affect user-facing output: negative bytes, NaN, fractional bytes, whitespace-only queries, and truncation exceeding maxLen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> https://claude.ai/code/session_01AfyN3rkDU7fn9G5SpZSM77
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review.
Tip: disable this comment in your organization's Code Review settings.
📝 WalkthroughWalkthroughAdds a Bun test suite for finops-formatting and small logic updates to Changes
Estimated Code Review Effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/opencode/test/altimate/tools/finops-formatting.test.ts (1)
51-56: Consider asserting exact length for the truncation test.The truncation logic for
maxLen=20should produce exactly 20 characters (17 from slice + 3 for "..."). WhiletoBeLessThanOrEqual(20)is correct, a stricter assertion would catch if the implementation under-truncates.💡 Optional: Use exact length assertion
test("long text truncated with ellipsis", () => { const long = "SELECT * FROM very_long_table_name WHERE id = 1" const result = truncateQuery(long, 20) - expect(result.length).toBeLessThanOrEqual(20) + expect(result.length).toBe(20) expect(result).toEndWith("...") })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/opencode/test/altimate/tools/finops-formatting.test.ts` around lines 51 - 56, The test "long text truncated with ellipsis" currently uses a non-strict length check; change the assertion for truncateQuery(long, 20) to expect exact length 20 (e.g., expect(result.length).toBe(20)) and keep the expect(result).toEndWith("...") to ensure the function returns the 17-char slice plus the 3-char ellipsis; update the test for truncateQuery accordingly so it fails if the function under- or over-truncates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/opencode/test/altimate/tools/finops-formatting.test.ts`:
- Around line 51-56: The test "long text truncated with ellipsis" currently uses
a non-strict length check; change the assertion for truncateQuery(long, 20) to
expect exact length 20 (e.g., expect(result.length).toBe(20)) and keep the
expect(result).toEndWith("...") to ensure the function returns the 17-char slice
plus the 3-char ellipsis; update the test for truncateQuery accordingly so it
fails if the function under- or over-truncates.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 60b5d1e2-5b90-4795-bcaa-09bc81c63501
📒 Files selected for processing (1)
packages/opencode/test/altimate/tools/finops-formatting.test.ts
`formatBytes`: - Guard `NaN`/`Infinity` with `Number.isFinite()` → returns "0 B" - Use `Math.abs()` for log calculation to handle negative byte deltas - Clamp unit index with `Math.max(0, Math.min(...))` to prevent `units[-1]` (fractional bytes) and overflow beyond PB `truncateQuery`: - Check post-trim result for empty string → return "(empty)" - Guard `maxLen <= 0` to prevent `slice(0, negative)` leaking content - Guard `maxLen < 4` to hard-truncate without ellipsis Tests updated from documenting bugs to asserting correct behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/opencode/src/altimate/tools/finops-formatting.ts (1)
14-16: Consider the interaction between whitespace-only input and smallmaxLen.The current check order means whitespace-only input returns
"(empty)"(7 characters) regardless ofmaxLen, which could exceed the requested length. For example,truncateQuery(" ", 2)returns"(empty)"instead of respecting the 2-character limit.Given the production callers use
maxLenvalues of 80 and 100 (per the relevant snippets), this is unlikely to cause issues in practice. If this behavior is intentional—treating"(empty)"as a semantic marker that takes precedence over length constraints—it would be helpful to add a brief comment documenting this design choice.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/opencode/src/altimate/tools/finops-formatting.ts` around lines 14 - 16, Reorder the early-return checks in truncateQuery so maxLen constraints are enforced before returning the "(empty)" marker: move the maxLen checks (maxLen <= 0 and maxLen < 4) above the oneLine emptiness check (the if (!oneLine) return "(empty)") so whitespace-only inputs are truncated to respect maxLen; alternatively, if the "(empty)" marker is intended to take precedence, add a short comment next to the if (!oneLine) branch explaining that design choice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/opencode/src/altimate/tools/finops-formatting.ts`:
- Around line 14-16: Reorder the early-return checks in truncateQuery so maxLen
constraints are enforced before returning the "(empty)" marker: move the maxLen
checks (maxLen <= 0 and maxLen < 4) above the oneLine emptiness check (the if
(!oneLine) return "(empty)") so whitespace-only inputs are truncated to respect
maxLen; alternatively, if the "(empty)" marker is intended to take precedence,
add a short comment next to the if (!oneLine) branch explaining that design
choice.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6c43f44a-b1d0-4688-b98a-9fa09bbecf6b
📒 Files selected for processing (2)
packages/opencode/src/altimate/tools/finops-formatting.tspackages/opencode/test/altimate/tools/finops-formatting.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/opencode/test/altimate/tools/finops-formatting.test.ts
Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387) into a single PR, discarding 4 duplicates (#391, #392, #393, #400). **New test coverage:** - `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema - `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback - `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants - `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides - `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing - `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases - `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles` - `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters - `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames - `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries - `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage - `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards - `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection **Bug fixes (discovered during testing):** - `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs - `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4 - `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys) - `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Consolidated into #403 |
* test: consolidated test coverage across 9 modules (133 new tests) Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387) into a single PR, discarding 4 duplicates (#391, #392, #393, #400). **New test coverage:** - `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema - `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback - `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants - `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides - `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing - `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases - `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles` - `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters - `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames - `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries - `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage - `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards - `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection **Bug fixes (discovered during testing):** - `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs - `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4 - `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys) - `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address code review findings — test artifact leakage and cleanup - summary-git-path.test.ts: use tmpdir() instead of projectRoot to prevent Storage.write() from polluting the developer's .opencode/storage/ directory - finops-role-access.test.ts: consolidate duplicate afterAll hooks to ensure ALTIMATE_TELEMETRY_DISABLED env var is cleaned up after tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
What does this PR do?
1.
formatBytesandtruncateQuery—src/altimate/tools/finops-formatting.ts(12 new tests)These pure utility functions power user-facing output in finops tools (
finops-expensive-queries.ts,finops-query-history.ts). Zero tests existed. Testing revealed 5 confirmed bugs:formatBytesbugs:"NaN undefined"— users see garbage when finops tools compute negative deltas (e.g. comparing periods where usage decreased)"NaN undefined"— propagated NaN from upstream calculations crashes display"512.00 undefined"—Math.floor(Math.log(0.5) / Math.log(1024))= -1, andunits[-1]isundefinedtruncateQuerybugs:""(empty string) instead of"(empty)"— the!textguard doesn't catch" "(truthy), but aftertrim()it becomes""which is returned directly by the length checkmaxLen < 3→ output exceeds maxLen —slice(0, 2-3)=slice(0, -1)keeps most of the string, then"..."is appended, producing 13+ chars for a 2-char limitNew coverage includes:
Type of change
Issue for this PR
N/A — proactive test coverage via
/test-discoveryHow did you verify your code works?
Checklist
https://claude.ai/code/session_01AfyN3rkDU7fn9G5SpZSM77
Summary by CodeRabbit
Bug Fixes
Tests