Skip to content

Cover change converter and config/adapter guard paths - #95

Open
hahn-kev-bot wants to merge 5 commits into
mainfrom
tests/converter-config-guards
Open

Cover change converter and config/adapter guard paths#95
hahn-kev-bot wants to merge 5 commits into
mainfrom
tests/converter-config-guards

Conversation

@hahn-kev-bot

@hahn-kev-bot hahn-kev-bot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

AI-generated summary

Fourth batch from the test-suite review, covering the bespoke IChange converter and the config/adapter guard branches — the converter owns all IChange (de)serialization yet its error paths and the OpaqueChange entity-id handling were untested.

ChangeConverterTests

  • Malformed-input throws: non-object root (Expected StartObject), empty object (Expected property name), non-string $type discriminator.
  • OpaqueChange entity-id parsing: parsed when present, defaults to Guid.Empty when missing, and nested JSON survives a round-trip.
  • OpaqueChange runtime contract: EntityType and NewEntity throw NotSupportedException; ApplyChange is a no-op.

ConfigTests

  • ChangeTypeListBuilder: duplicate Add is idempotent; Add after freeze throws.
  • ObjectTypeListBuilder: Add/DefaultAdapter after freeze throws; DefaultAdapter() returns the same instance on repeat calls; Adapt dispatch covered for success, a non-IObjectBase argument (throws), and no-provider-matches with two providers registered (throws).

DerivedTypeHelperTests (new file) — duplicate derived-type registration throws; GetEntityDiscriminator throws when the instance type is not assignable to the base. This helper is the guard behind adapter double-registration and had zero references.

Test-only; no production code changed.

Test plan

  • dotnet test on the affected classes passes (29/29 locally).

Summary by CodeRabbit

  • Tests
    • Expanded coverage for invalid change data, opaque changes, nested JSON preservation, and entity ID handling.
    • Added validation tests for configuration freezing, duplicate registrations, adapter behavior, and unsupported adaptations.
    • Added tests for derived-type registration and discriminator validation.

Adds coverage for the bespoke IChange converter and the config/adapter
guard branches, which were largely untested:
- PeekThenConcreteChangeConverter malformed-input throws (non-object root,
  empty object, non-string $type) and OpaqueChange EntityId parsing
  (present, missing-defaults-to-empty, nested-json round-trip).
- OpaqueChange runtime contract: EntityType and NewEntity throw, ApplyChange
  is a no-op.
- ChangeTypeListBuilder duplicate-add idempotency and frozen guard.
- ObjectTypeListBuilder frozen guard, DefaultAdapter singleton reuse, and
  Adapt dispatch (success, non-IObjectBase throw, no-provider-matches throw).
- DerivedTypeHelper duplicate-type throw and wrong-base throw.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@hahn-kev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6982da1f-10ed-4c57-9b95-0b2c195bde24

📥 Commits

Reviewing files that changed from the base of the PR and between 0a10144 and 135c154.

📒 Files selected for processing (2)
  • src/SIL.Harmony.Tests/ChangeConverterTests.cs
  • src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs
📝 Walkthrough

Walkthrough

The pull request adds tests for JSON change conversion, opaque changes, configuration builder state, object adaptation, and derived-type registration and lookup.

Changes

Behavior coverage

Layer / File(s) Summary
Change conversion and opaque changes
src/SIL.Harmony.Tests/ChangeConverterTests.cs
Tests validate JSON structure and discriminator errors, opaque-change entity IDs, nested JSON round trips, unsupported operations, and no-op application.
Configuration and object adaptation
src/SIL.Harmony.Tests/ConfigTests.cs
Tests cover duplicate registration, builder freezing, default adapter reuse, direct adaptation, and adaptation failures.
Derived-type registration and lookup
src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs
Tests cover duplicate registration, multiple derived types, and rejection of non-assignable discriminator types.

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

Possibly related PRs

  • sillsdev/harmony#80: Introduces the OpaqueChange, converter, and configuration behaviors covered by these tests.
  • sillsdev/harmony#85: Covers ChangeTypeListBuilder freezing and configuration timing.
  • sillsdev/harmony#91: Modifies OpaqueChange behavior covered by ChangeConverterTests.cs.

Suggested reviewers: myieye

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main test coverage added for the change converter and configuration/adapter guard paths.
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 tests/converter-config-guards

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.

The lambda inferred Func<Type>, which FluentAssertions did not reliably
invoke (passed in Debug, failed in Release CI with 'no exception thrown').
Use an explicit Action with a discard so the throwing getter always runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs (2)

13-18: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use a different discriminator for the duplicate registration.

Both calls use "Word". This test cannot prove that AddDerivedType rejects the duplicate DerivedType rather than only rejecting a duplicate discriminator. Keep typeof(Word) and change the second discriminator.

🤖 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 `@src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs` around lines 13 -
18, Update the duplicate-registration test around AddDerivedType so the second
call still uses typeof(Word) but supplies a different discriminator from "Word".
Keep the existing exception assertion, ensuring the test verifies duplicate
derived-type rejection rather than duplicate-discriminator rejection.

24-28: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the stored registration values.

The count assertion can pass when the list contains incorrect JsonDerivedType values. Assert that the list contains Word with "Word" and Definition with "Definition".

🤖 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 `@src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs` around lines 24 -
28, Update the test around the dictionary registration and its count assertion
to verify the stored JsonDerivedType values, asserting entries for Word with
"Word" and Definition with "Definition" rather than only checking the list
count.
🤖 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 `@src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs`:
- Around line 13-18: Update the duplicate-registration test around
AddDerivedType so the second call still uses typeof(Word) but supplies a
different discriminator from "Word". Keep the existing exception assertion,
ensuring the test verifies duplicate derived-type rejection rather than
duplicate-discriminator rejection.
- Around line 24-28: Update the test around the dictionary registration and its
count assertion to verify the stored JsonDerivedType values, asserting entries
for Word with "Word" and Definition with "Definition" rather than only checking
the list count.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 59005f4a-b8b9-4437-8d3e-0d4773d84c8b

📥 Commits

Reviewing files that changed from the base of the PR and between 03f609f and 0a10144.

📒 Files selected for processing (3)
  • src/SIL.Harmony.Tests/ChangeConverterTests.cs
  • src/SIL.Harmony.Tests/ConfigTests.cs
  • src/SIL.Harmony.Tests/Helpers/DerivedTypeHelperTests.cs

hahn-kev and others added 2 commits August 6, 2026 16:51
The FluentAssertions delegate form did not reliably invoke the getter
under the CI Release SDK (passed locally, failed in CI). Assert.Throws'
Func overload returns and consumes the property value, guaranteeing the
throwing getter runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- duplicate-registration test now uses a different discriminator for the
  second call, proving the guard rejects a duplicate DerivedType rather
  than a duplicate discriminator.
- different-types test asserts the stored JsonDerivedType values instead
  of only the count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hahn-kev-bot

Copy link
Copy Markdown
Collaborator Author

Addressed both CodeRabbit nitpicks on DerivedTypeHelperTests.cs:

  • AddDerivedType_Duplicate_Throws now uses a different discriminator ("WordAgain") for the second registration, so it proves the guard rejects a duplicate DerivedType rather than a duplicate discriminator.
  • AddDerivedType_DifferentTypesUnderSameBase_Succeeds now asserts the stored JsonDerivedType values (Word"Word", Definition"Definition") instead of only the count.

🤖 Addressed by Claude Code

Every delegate-wrapped access of the throw-bodied getter (FluentAssertions
Func/Action and Assert.Throws' Func overload) failed to observe the
exception under the CI SDK. Access the getter directly in the method body
inside a try/catch and consume the value via GC.KeepAlive so the call
cannot be elided.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants