test: fill the two empty util test stubs - #215
Open
bobbyg603 wants to merge 1 commit into
Open
Conversation
…s stubs Both files were empty TODOs, which is why the rate limiter's shared-state behaviour and the options merge went unverified. These pin current behaviour rather than the behaviour we want. Where a test encodes something arguably wrong -- no per-signature dedup so an unrelated exception inside the window is dropped rather than deferred, one static window shared by every client in the process, an unsynchronized check-then-set, a wall-clock window that a backwards clock jump wedges, whitespace treated as a set value, a non-idempotent attachment merge -- the test says so in a comment so the redesign in #170 knows what it is free to change. The limiter's only state is a private static DateTime, so the fixture resets it before and after every test and writes an aged timestamp instead of sleeping out the real three second window. That makes the tests order-independent, keeps them fast, and leaves no residue for the rest of the suite. Nothing else in the suite uses the default delegate, so the two cannot interfere. The concurrency test asserts only what must hold -- at least one caller is admitted, no more than all of them, and the window is closed afterwards -- because the exact count is a race and a flaky test here is worse than no test. Attachments-is-null is deliberately left uncovered; the inverted guard that makes it throw is being fixed in #161 with its own test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds comprehensive NUnit coverage for two previously-empty util test stubs, documenting current (including known-defective) behaviors for the rate limiter and post-options merge logic, to support future redesign work.
Changes:
- Implemented a full
ShouldPostExceptionImplrate-limiter test suite, including deterministic static-state reset via reflection and a concurrency-focused test. - Implemented a full
ReportPostOptionsExtensions.SetNullOrEmptyValuesmerge-behavior test suite, including pinned “known defects” behaviors and attachment/attribute merge semantics.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| Tests/Runtime/Util/ShouldPostExceptionImplTests.cs | Adds deterministic, state-resetting tests for the ShouldPostExceptionImpl static time-window rate limiter (including concurrency). |
| Tests/Runtime/Util/ExceptionPostOptionsExtensionsTests.cs | Adds merge-behavior tests for SetNullOrEmptyValues, covering string defaults, attachments, and attributes (including pinned defect cases). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1
to
+6
| using BugSplatUnity.Runtime.Settings; | ||
| using BugSplatUnity.Runtime.Util; | ||
| using NUnit.Framework; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
| using System.IO; |
daveplunkett
approved these changes
Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #167
Tests/Runtime/Util/ShouldPostExceptionImplTests.csandTests/Runtime/Util/ExceptionPostOptionsExtensionsTests.cswere empty// TODOstubs. This fills both with 24 tests. No production code changes.These document current behaviour, not desired behaviour
Both units have defects that are deliberately not fixed here. Every test that encodes one carries a comment saying so, so the redesign in #170 knows which assertions it is free to break:
IClientSettingsRepositorydefaults to the same static method, so two BugSplat clients in one process rate-limit each otherDateTime.Now, a local wall clock — DST or an NTP correction wedges the limiterIsNullOrEmpty, notIsNullOrWhiteSpace, so the report ships a field that renders blankSetNullOrEmptyValuestwice duplicates attachmentsclientSettings.Attributes == nullthrowsNullReferenceExceptionforeachdereferences it unguarded, so the failure surfaces as an unhandled exception inside the report pathHow the shared static state is handled
ShouldPostExceptionImpl's entire state is one private staticDateTime, so a naive fixture would be order-dependent and would need multi-second sleeps. Both problems are solved the same way: the fixture reflects on that field to reset it to its declared initial value in[SetUp]and[TearDown], and tests that need an aged or skewed window write the field instead of sleeping.Consequences, all verified:
[TearDown]restores the initial value, so this fixture cannot perturb the rest of the suite.ShouldPostException), so there is no interference in either direction.[OneTimeSetUp]asserts the field still exists, so if B3: Rate limiter — per-signature dedup, suppressed count, honest docs #170 renames or removes it these tests fail loudly with an explanatory message instead of NREing.The concurrency test is the one place where an exact assertion would be a coin flip, so it asserts only what must always hold — at least one caller admitted, no more than all of them, and the window closed afterwards — with a comment explaining that the exact count becomes assertable once #170 adds synchronization. A flaky test here would be worse than no test.
Overlap with #161
#161 is fixing the inverted
Attachments?.Count != 0guard concurrently and adding a tightly-scoped test toExceptionPostOptionsExtensionsTests.cs. The null-Attachmentscase is intentionally left uncovered here so this PR does not assert the behaviour that PR is changing. Everything else about the attachment merge is covered (empty list, non-empty list, append-not-replace, double-apply). Expect a small textual conflict in that file since both PRs replace the same stub body; the two sets of tests are complementary and should merge by keeping both.Note the fixture class name (
ExceptionPostOptionsExtensionsTests) does not match the unit (ReportPostOptionsExtensions) — kept as-is to preserve the filename #167 and #161 both refer to.Verification
Both units are plain C# apart from one
UnityEngine.Debug.Logcall, so the tests were actually executed, not just compiled. A throwawaydotnet testproject (net10.0, NUnit 3.14 + NUnit3TestAdapter 4.5 + Microsoft.NET.Test.Sdk 17.11) compiled the two units plus their dependencies against Unity 6000.5.6f1's realUnityEngine.CoreModule.dllandBugSplatDotNetStandard.dll:Runtime/**+Tests/**tree compiles against Unity's assemblies and Unity's NUnit build with 0 errors and only the two pre-existingCS0649warnings inBugSplat.cs.One harness detail worth recording:
UnityEngine.Debug.Logbottoms out in an ECall that only exists inside the Unity player, so under plaindotnet testit throwsSecurityException: ECall methods must be packaged into a system module— and on a background thread that aborts the run. The harness installed a no-opILogHandlerviaDebug.unityLogger.logHandlerto get past it. That stub lives only in the throwaway project, not in this branch; under Unity's own test runnerDebug.Logworks normally andLogAssertignoresLogType.Log.🤖 Generated with Claude Code