fix: correct inverted null guard on client settings attachments - #208
Open
bobbyg603 wants to merge 1 commit into
Open
fix: correct inverted null guard on client settings attachments#208bobbyg603 wants to merge 1 commit into
bobbyg603 wants to merge 1 commit into
Conversation
SetNullOrEmptyValues guarded the attachment copy with `clientSettings.Attachments?.Count != 0`. When Attachments is null the null-conditional yields a null int?, and `null != 0` is true, so the guard falls through into `AddRange(null)` and throws ArgumentNullException. The guard was inverted: it only skips the copy in the one case where the copy is harmless (an empty list) and admits it in the case that throws. `?.Count > 0` lifts correctly - a null Attachments compares false - so the copy runs only when there is something to copy. Latent on main: WebGLClientSettingsRepository initializes the list inline and DotNetStandardClientSettingsRepository delegates to BugSplatDotNetStandard.BugSplat.Attachments, which the shipped DLL initializes to an empty list. Any future settings repository that leaves the property null would crash every report post. Fills the empty ExceptionPostOptionsExtensionsTests stub with coverage for the null, empty, and populated cases. The null test fails with the exact ArgumentNullException against the pre-fix guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes a latent ArgumentNullException in ReportPostOptionsExtensions.SetNullOrEmptyValues by correcting an inverted null/empty guard when copying client settings attachments, and adds runtime-unit tests to prevent regression.
Changes:
- Corrected attachments guard from
!= 0to> 0to properly skip null/empty attachment lists. - Added NUnit tests covering null, empty, and populated attachments behavior, plus a regression check for shipped settings initialization.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Runtime/Util/ReportPostOptionsExtensions.cs | Fixes the inverted null/empty guard to prevent AddRange(null) when attachments are unset. |
| Tests/Runtime/Util/ExceptionPostOptionsExtensionsTests.cs | Adds regression tests for SetNullOrEmptyValues attachment handling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+52
to
+56
| [Test] | ||
| public void Attachments_ShippedClientSettingsRepository_ShouldBeInitialized() | ||
| { | ||
| Assert.IsNotNull(new WebGLClientSettingsRepository().Attachments); | ||
| } |
| namespace BugSplatUnity.RuntimeTests.Util | ||
| { | ||
| class ExceptionPostOptionsExtensionsTests | ||
| public class ExceptionPostOptionsExtensionsTests |
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 #161
Problem
Runtime/Util/ReportPostOptionsExtensions.csguarded the attachment copy with:When
Attachmentsis null,?.Countyields a nullint?andnull != 0is true, so the guard falls through intoAddRange(null)and throwsArgumentNullException. The guard was exactly inverted: it skipped the copy only in the one case where copying is harmless (an empty list) and admitted it in the case that throws.Fix
>on a liftedint?is false when the operand is null, so a nullAttachmentscorrectly skips the copy.Verification of the "latent today" claim
Confirmed still latent on
main— both shipped settings repositories initialize the list:WebGLClientSettingsRepository.Attachmentsis initialized inline (= new List<FileInfo>()).DotNetStandardClientSettingsRepository.Attachmentsdelegates toBugSplatDotNetStandard.BugSplat.Attachments. I instantiated the vendoredRuntime/Plugins/BugSplatDotNetStandard.dlldirectly and confirmed the property is non-null (empty list) on a fresh instance.So nothing crashes today, but any new
IClientSettingsRepositoryimplementation that leaves the property null would throw on every report post.Other collections in the file
I checked the rest of
SetNullOrEmptyValuesand greppedRuntime/andEditor/for?.Count/?.Length. The inverted guard appeared exactly once — the line fixed here is the only instance in the repo.One adjacent observation, left unchanged to keep this fix minimal:
foreach (var attribute in clientSettings.Attributes)has no null guard at all, so it wouldNullReferenceExceptionunder the same "future repository leaves it null" scenario. Same latency argument (both repos initializeAttributes), different pattern from the inverted guard this issue describes. Happy to fold it in if a reviewer prefers.Tests
Tests/Runtime/Util/ExceptionPostOptionsExtensionsTests.cswas an empty TODO stub — precisely the file that should have caught this. Filled it with coverage scoped to the null-guard behaviour:SetNullOrEmptyValues_NullAttachments_ShouldNotThrowSetNullOrEmptyValues_EmptyAttachments_ShouldNotAddAttachmentsSetNullOrEmptyValues_PopulatedAttachments_ShouldAddAttachmentsAttachments_ShippedClientSettingsRepository_ShouldBeInitialized(regression guard on the "latent" premise)The null test is a genuine regression test: reverted to
!= 0, it fails with exactlySystem.ArgumentNullException: Value cannot be null. (Parameter 'collection')atList.AddRange/ReportPostOptionsExtensions.cs:12. Restored, it passes.Note
#167 is concurrently expanding this same file (it fills both empty stubs,
ShouldPostExceptionImplTests.csandExceptionPostOptionsExtensionsTests.cs). I kept this change tightly scoped to the null-guard behaviour, but expect a small merge inExceptionPostOptionsExtensionsTests.cs.How I verified
Unity's test runner was not available here, so I compiled and ran these types out-of-editor — they are plain C# with no Unity runtime dependency.
pkgcheck.csproj(wholeRuntime/**+Tests/Runtime/**against the Unity managed DLLs and the vendoredBugSplatDotNetStandard.dll) —dotnet buildsucceeds, 0 errors, only the two pre-existingCS0649warnings inBugSplat.cs.ReportPostOptions, the settings repositories,ReportPostOptionsExtensions,ShouldPostExceptionImpl,NativeSyncDictionary, plusExceptionPostOptionsExtensionsTestsandNativeSyncDictionaryTests) with NUnit 3.14 + NUnit3TestAdapter + Microsoft.NET.Test.Sdk.15 = my 4 new tests + the 11 existing
NativeSyncDictionaryTests. The[UnityTest]-based suites need the Unity editor and were compile-checked only, not executed.🤖 Generated with Claude Code