Skip to content

test(tools): add unit tests for annotation state, math utilities, store filters, and synchronizers#2790

Merged
sedghi merged 3 commits into
mainfrom
cornerstoneImprovedTesting
Jul 8, 2026
Merged

test(tools): add unit tests for annotation state, math utilities, store filters, and synchronizers#2790
sedghi merged 3 commits into
mainfrom
cornerstoneImprovedTesting

Conversation

@sedghi

@sedghi sedghi commented Jul 8, 2026

Copy link
Copy Markdown
Member

Context

Second round of the test-coverage campaign (round 1: #2789, packages/core GenericViewport). packages/tools had only 6.3% jest line coverage — the karma browser suite owns interactive tool testing, but the pure logic underneath (state management, geometry math, hit-test filters, synchronization) was nearly untested. This PR targets the 5 most critical jsdom-testable areas, chosen from a per-file coverage audit.

What is added

427 new jest tests across eight files in packages/tools/test/, no source changes:

File Targets Tests
annotationStateManagement.jest.js annotation state CRUD, FoR manager save/restore, locking/selection/visibility + event payloads, groups, parent/child 112
utilities/polylineMath.jest.js + utilities/polylineBooleanOps.jest.js polyline predicates, convex hull, decimation, segment intersections, intersect/subtract/merge boolean ops 82
utilities/geometryPrimitives.jest.js ellipse/circle/line/rectangle/aabb/sphere/angle/point/vec2/vec3 primitives 86
synchronizerCore.jest.js Synchronizer class lifecycle (real DOM event dispatch), SynchronizerManager, camera/VOI/slab/presentation callbacks 51
utilities/viewportFilters.jest.js FoR / orientation / parallel-normal / tool-enabled render fan-out filters 21
storeToolFilters.jest.js per-mouse-move tool and handle hit-test filters, cancelActiveManipulations, addTool registry 28
utilities/planarAndBounds.jest.js annotation slice/plane display filtering, world width/height, plane-AABB intersection, bounding boxes 47

Coverage over packages/tools/src

Overall jest coverage: 6.3% -> 12.6% lines, 7.5% -> 15.0% branches.

Area Lines
utilities/math 14.0 -> 86.2
stateManagement/annotation 0 -> 71.9
utilities/viewportFilters 0 -> 98.1
utilities/boundingBox 2.1 -> 100
synchronizers 41.7 -> 81.0
utilities/planar 0 -> 56.4
store 0.5 -> 32.2

Latent bugs surfaced (pinned by regression tests documenting current behavior; no behavior changed)

  • FrameOfReferenceSpecificAnnotationManager.getNumberOfAnnotations(groupKey) without a toolName always returns 0 — the map has no .length, so the count-all summation loop is unreachable.
  • annotationVisibility.show/hide and single-UID deselectAnnotation lack the null-guard that annotationLocking has, and throw a TypeError when the annotation was already removed from the manager.
  • store/addTool.ts removeTool: if (!state.tools[toolName] !== undefined) is always true, making the documented "not added" throw unreachable.
  • getBoundingBoxAroundShapeWorld: the world-space clamp derives both clip bounds from the same dimensions[axis] scalar, producing an inverted min/max range whenever clamping applies (the function has zero callers in src).
  • intersectPolylines/subtractPolylines: when overlap corners land exactly on existing vertices of the other polygon (e.g. two 10x10 squares offset by 5), augmented-list consolidation mispairs intersections and the traced boundary is garbled.
  • liangBarksyClip rejects segments lying exactly on a clip-window edge as outside (strict inequality in the degenerate branch).
  • ellipse/pointInEllipsoidWithConstraint is an exported stub whose entire body is commented out (always returns undefined).
  • addCanvasPointsToArray: stray console.log in production source; point-count math divides both x and y distances by spacing[0], never using spacing[1].

A follow-up PR can address these individually; each has a test adjacent to the behavior making the fix straightforward to verify.

Verification

Full packages/tools jest suite: 33 suites, 618 passed, 2 skipped. No changes under packages/tools/src or to existing tests.

Summary by CodeRabbit

  • Tests
    • Added extensive automated coverage for annotation state management, synchronizers, viewport filtering, and store/tool selection logic.
    • Expanded validation for geometry, polyline, plane, and bounding-box utilities, including edge cases and known boundary behaviors.
    • Improved regression coverage for selection, locking, visibility, cancellation, and synchronization workflows.

sedghi added 3 commits July 8, 2026 13:53
…modality camera math

Adds 279 jest tests across six new test files targeting the most
critical undertested areas of the GenericViewport architecture:

- genericViewportBase.jest.js: GenericViewport base class binding
  lifecycle, mount races (stale requests, destroy mid-load, source
  role demotion), presentation merge/fan-out, view state propagation,
  camera events, destroy semantics, and genericViewportDisplaySetAccess
- planarSliceBasis.jest.js: slice basis derivation for stack images
  and volumes across orientations, anisotropic spacing, rotated and
  flipped direction matrices, and image id index resolution
- planarViewReference.jest.js: planar view reference build/match APIs
  and PlanarViewReferenceController navigation (world point to slice,
  opposite-normal index flip, plane-restriction reorientation)
- planarRenderCamera.jest.js: resolvePlanarICamera and
  derivePlanarPresentation round-trips (zoom, pan, rotation, flips,
  display areas), renderer/actor application, clipping ranges, and
  PlanarVolumeResolvedView parity with the existing stack suite
- modalityViewportCameras.jest.js: Video/ECG/Volume3D viewport camera
  math (canvas mappings, scale modes, anchor/pan round-trips)
- wsiTransformUtils.jest.js: WSI world/index/canvas transforms and
  color transform branches

Coverage over src/RenderingEngine/GenericViewport rises from 33.7% to
44.0% lines and 26.3% to 38.1% branches, with the targeted modules at
89-100% lines.
…re filters, and synchronizers

Adds 427 jest tests across eight new test files targeting the most
critical undertested pure-logic areas of packages/tools (karma browser
tests continue to own interactive tool coverage):

- annotationStateManagement.jest.js: annotation state CRUD through the
  FrameOfReferenceSpecificAnnotationManager, save/restore round-trips,
  locking/selection/visibility semantics and event payloads, annotation
  groups, parent/child relationships
- polylineMath.jest.js + polylineBooleanOps.jest.js: polyline
  predicates (containsPoint, winding, closedness, AABB), convex hull,
  decimation, segment intersection variants, robust intersection, and
  the intersect/subtract/merge boolean-op workhorses verified via area
  and point-membership properties
- geometryPrimitives.jest.js: ellipse/circle/line/rectangle/aabb/
  sphere/angle/point/vec2/vec3 primitives including pointInEllipse,
  liangBarksyClip, and distance helpers
- synchronizerCore.jest.js: Synchronizer class lifecycle with real DOM
  event dispatch, SynchronizerManager factories, and camera/VOI/slab/
  presentation sync callbacks
- viewportFilters.jest.js: frame-of-reference, orientation, parallel
  normal, and tool-enabled render fan-out filters
- storeToolFilters.jest.js: per-mouse-move tool/handle hit-test
  filters, cancelActiveManipulations, addTool/state registry
- planarAndBounds.jest.js: annotation slice/plane display filtering,
  world width/height derivation, plane-AABB intersection, bounding box
  helpers

Tools package jest coverage rises from 6.3% to 12.6% lines overall,
with the targeted areas at: utilities/math 86%, annotation state 72%,
viewportFilters 98%, boundingBox 100%, synchronizers 81%.

Several latent product bugs were found and pinned by regression tests
without changing behavior; see the test files for details (notably:
manager getNumberOfAnnotations group-count dead path, missing
null-guards in annotation visibility/selection, removeTool unreachable
throw, getBoundingBoxAroundShapeWorld inverted clamp, boolean-op
vertex-coincident corner mispairing, liangBarksyClip boundary
rejection).
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds eight new Jest test files under packages/tools/test covering annotation state management, store tool filters, the Synchronizer system, geometry primitives, planar/bounding-box utilities, polyline boolean operations, polyline math, and viewport filters, with no source code or public API changes.

Changes

New Jest test suites

Layer / File(s) Summary
Annotation state management
packages/tools/test/annotationStateManagement.jest.js
Tests annotation CRUD, group manager, locking, selection, visibility, AnnotationGroup, and reset behavior with mocked core events/UUID/deepClone.
Store tool filters
packages/tools/test/storeToolFilters.jest.js
Tests tool-with-annotation filtering, moveable-annotation/handle filters, manipulation cancellation, and tool registry (addTool/removeTool).
Synchronizer core
packages/tools/test/synchronizerCore.jest.js
Tests Synchronizer/SynchronizerManager event dispatch/teardown and sync callbacks for camera, VOI, slab thickness, presentation view, and coplanarity.
Geometry primitives
packages/tools/test/utilities/geometryPrimitives.jest.js
Tests ellipse/circle, line intersection, distance-to-point, AABB, sphere, angle, clipping, and interpolation utilities.
Planar and bounds utilities
packages/tools/test/utilities/planarAndBounds.jest.js
Tests annotation slice/plane filtering, display filtering, world-width/height, AABB-plane intersection, bounding boxes, and index snapping.
Polyline boolean ops and math
packages/tools/test/utilities/polylineBooleanOps.jest.js, packages/tools/test/utilities/polylineMath.jest.js
Tests polygon intersect/subtract/merge operations and core polyline math including containment, area, normals, intersections, decimation, and projection.
Viewport filters
packages/tools/test/utilities/viewportFilters.jest.js
Tests frame-of-reference, parallel-normal, orientation, and tool-enabled viewport filters plus composed viewport-id resolution.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: wayfarer3130

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding unit tests for tools-related annotation, math, store, and synchronizer code.
Description check ✅ Passed The description covers context, changes, coverage impact, bug notes, and verification, matching the template's core intent well.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cornerstoneImprovedTesting

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/tools/test/utilities/polylineMath.jest.js (1)

31-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing beforeEach import from @jest/globals.

Line 701 uses beforeEach but it is not imported at line 31 where only { describe, it, expect } are imported from @jest/globals. If Jest globals are not enabled in the config, this will throw a ReferenceError. Even if globals happen to be available, the import style is inconsistent — all other Jest globals are explicitly imported.

♻️ Proposed fix
 import { describe, it, expect } from '`@jest/globals`';
+import { beforeEach } from '`@jest/globals`';

Or consolidate into a single import:

-import { describe, it, expect } from '`@jest/globals`';
+import { describe, it, expect, beforeEach } from '`@jest/globals`';

Also applies to: 701-701

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tools/test/utilities/polylineMath.jest.js` around lines 31 - 32, The
test file is using beforeEach without importing it from `@jest/globals`, which can
cause a ReferenceError and is inconsistent with the existing explicit Jest
imports. Update the import at the top of polylineMath.jest.js to include
beforeEach alongside describe, it, and expect, and keep the test setup in the
same style used by the rest of the file so the beforeEach call near the test
block is covered.
packages/tools/test/utilities/geometryPrimitives.jest.js (1)

372-378: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the misleading it() description.

The test name begins with "is 0 for a point inside the rectangle" but the assertion expects 5, not 0. While the parenthetical clarifies the actual behavior, the leading text is confusing in test failure output — a developer sees "is 0" next to "Expected: 5".

♻️ Suggested rename
-  it('is 0 for a point inside the rectangle (closest edge distance still computed from segments, so on-boundary is 0, but strictly-inside is > 0 by design)', () => {
+  it('returns positive distance to nearest edge for a strictly-interior point (not signed inside distance)', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tools/test/utilities/geometryPrimitives.jest.js` around lines 372 -
378, Rename the misleading test description in geometryPrimitives.jest.js for
the `rectangleDistanceToPoint` case so it matches the asserted behavior: the
current `it()` title says the result is 0 for an inside point, but the
expectation is `5`. Update the description to clearly state that a strictly
inside point returns the distance to the nearest edge, keeping the existing
assertion and helper reference (`rectangleDistanceToPoint`) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/tools/test/utilities/geometryPrimitives.jest.js`:
- Around line 372-378: Rename the misleading test description in
geometryPrimitives.jest.js for the `rectangleDistanceToPoint` case so it matches
the asserted behavior: the current `it()` title says the result is 0 for an
inside point, but the expectation is `5`. Update the description to clearly
state that a strictly inside point returns the distance to the nearest edge,
keeping the existing assertion and helper reference (`rectangleDistanceToPoint`)
unchanged.

In `@packages/tools/test/utilities/polylineMath.jest.js`:
- Around line 31-32: The test file is using beforeEach without importing it from
`@jest/globals`, which can cause a ReferenceError and is inconsistent with the
existing explicit Jest imports. Update the import at the top of
polylineMath.jest.js to include beforeEach alongside describe, it, and expect,
and keep the test setup in the same style used by the rest of the file so the
beforeEach call near the test block is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4a895a6-a3da-4d1d-961e-c308b2dde7aa

📥 Commits

Reviewing files that changed from the base of the PR and between 1513e07 and 28661c5.

📒 Files selected for processing (8)
  • packages/tools/test/annotationStateManagement.jest.js
  • packages/tools/test/storeToolFilters.jest.js
  • packages/tools/test/synchronizerCore.jest.js
  • packages/tools/test/utilities/geometryPrimitives.jest.js
  • packages/tools/test/utilities/planarAndBounds.jest.js
  • packages/tools/test/utilities/polylineBooleanOps.jest.js
  • packages/tools/test/utilities/polylineMath.jest.js
  • packages/tools/test/utilities/viewportFilters.jest.js

@sedghi
sedghi merged commit 34e13d7 into main Jul 8, 2026
16 of 17 checks passed
@sedghi
sedghi deleted the cornerstoneImprovedTesting branch July 8, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant