Skip to content

Add round-trip deserialization test for non-default AppSettings values#41

Open
anagnorisis2peripeteia wants to merge 1 commit into
hbashton:mainfrom
anagnorisis2peripeteia:tests/appsettings-deserialization
Open

Add round-trip deserialization test for non-default AppSettings values#41
anagnorisis2peripeteia wants to merge 1 commit into
hbashton:mainfrom
anagnorisis2peripeteia:tests/appsettings-deserialization

Conversation

@anagnorisis2peripeteia

@anagnorisis2peripeteia anagnorisis2peripeteia commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

While going through the settings-code coverage gaps in #37, I noticed the AppSettingsDTO XML round-trip only exercises these proxy setters with their default values. CheckSettingsRead deserializes the fixture but only asserts LastChecked, so a string-proxy setter that silently failed to assign would still go unnoticed.

This adds one test, CheckSettingsDeserializeNonDefaultValues, that deserializes a <Profile> with non-default values for the …String proxy settings (the ones that parse via bool/int/Enum.TryParse and assign the typed property) and asserts each typed property came through. Because every value differs from its default, a setter that drops the assignment—or inverts the TryParse guard—now yields the wrong value and fails the assertion.

It covers about 20 settings, including DisconnectBTAtStop, SwipeProfiles, QuickCharge, AppIcon (TrayIconChoice.Colored), AppTheme (AppThemeChoice.Dark), and the DeviceOptions.*SupportSettings.Enabled flags. I deliberately skipped UseExclusiveMode, StartMinimized, and MinimizeToTaskbar, which go through XmlDataUtilities.StrToBool; those read cleanest as a small follow-up.

Before/after proof:

AppSettingsDTO mutation run Killed Survived Score
Before: existing tests 4 177 2.2%
After: with this test 40 143 21.9%

For a direct red/green check, I removed the same representative assignment (DisconnectBTAtStop = temp) in isolated base and HEAD worktrees and ran this exact command on both:

dotnet test .\DS4WindowsTests\DS4WindowsTests.csproj -c Release -p:Platform=x64 --verbosity normal --filter "FullyQualifiedName=DS4WindowsTests.AppSettingsTests.CheckSettingsDeserializeNonDefaultValues"
  • Base ba4bdcb7 with the injected fault: exit 0; no matching regression test exists.
  • HEAD 4f932abf with the same fault: exit 1; the new test fails on Expected:<True>. Actual:<False>.
  • Restored HEAD: exit 0; the new test passes.

The full sanitized logs and machine-readable proof manifest are attached. This is test-only with no renderable UI change, so terminal and mutation evidence are the relevant proof rather than screenshots.


Local review history: round 1 https://gist.github.com/anagnorisis2peripeteia/29e14a33c013c9f7da6fcb10e4813d26 · round 2 https://gist.github.com/anagnorisis2peripeteia/ab31cc0bb9a970a81591a2f06399769c

Proof manifest

Before / After (same command, same machine)

dotnet test DS4WindowsTests\DS4WindowsTests.csproj -c Release -p:Platform=x64 --filter "Name!=CheckSettingsSave&Name!=CheckWriteProfile&Name!=CheckJaysProfileRead&Name!=CheckSettingsRead"
Run Result
Base + injected fault (neutered DisconnectBTAtStop assignment) ✅ suite passes — fault missed (the coverage gap)
This branch + the same fault CheckSettingsDeserializeNonDefaultValues fails — fault caught
This branch, clean ✅ suite passes

Fault-injection proof (test-only PR): neutered the DisconnectBTAtStopString setter's assignment identically on base and this branch, ran the same focused suite on both. Base + fault: suite passes (fault missed). This branch + fault: CheckSettingsDeserializeNonDefaultValues fails (fault caught). Clean branch: suite passes. Mutation delta on AppSettingsDTO.cs: 2.2% -> 21.9% (36 more mutants killed), posted above.

Manifest + raw run outputs: https://gist.github.com/anagnorisis2peripeteia/4b9eb34a1e5123d9e791d1bc2dcd1f9b

The XML string-proxy setters in AppSettingsDTO (bool/int/enum TryParse ->
assign) were unasserted: mutation testing showed that negating the parse guard
or deleting the assignment both survived, because the existing fixture only
used default values. This adds a round-trip test that deserializes non-default
values and asserts each typed property, so a setter that fails to assign is
now caught.

Part of hbashton#37
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Before/after behavioral evidence for this coverage addition — mutation testing (Stryker.NET) of the file under test, AppSettingsDTO.cs:

Killed Survived Score
Before (existing tests only) 4 177 2.2%
After (with CheckSettingsDeserializeNonDefaultValues) 40 143 21.9%

The new test kills 36 previously-surviving mutants — the string-proxy setters (bool/int/Enum.TryParse → assign) that the existing default-valued deserialization tests don't exercise (deleting the assignment or negating the parse guard both survived before, because the fixture matched the defaults). Measured on **/AppSettingsDTO.cs, both runs on the same base.

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