Context
Two behaviours in ScanDeckSettings exist purely to stop a preference file from breaking the app, and both are documented as such in the source:
- The custom
init(from:) decodes field by field — "A settings file that fails to decode costs the operator every other preference in it".
ScanDeckSettingsStore.load() falls back to .default via try? — "an app that will not start because of a preference".
Neither promise is checked. A future refactor to a synthesised Codable would silently delete both and every existing test would still pass.
grep -rn 'ScanDeckSettingsStore' Tests/ hits only four sites and all four merely construct the store to inject into the presentation model. Every autoContinueSeconds assertion goes through model.autoContinueSeconds, which tests the model's clamping, not the decoder.
What to change
New file Tests/ScanDeckCoreTests/ScanDeckSettingsTests.swift, using InMemoryScanDeckSettingsStorage — never UserDefaultsScanDeckSettingsStorage(), which is the production default and would corrupt the operator's real preferences.
Cases worth writing:
- JSON carrying only
preferredScannerName decodes, and autoContinueSeconds falls back to its default.
- JSON carrying an unknown future key still decodes rather than throwing.
- Non-JSON bytes in storage yield
.default from load() rather than throwing.
- A
save → load round trip preserves both fields.
Use Swift Testing, not XCTest.
How to verify
swift test --filter ScanDeckSettings
swift test -c release
A good check that the tests are load-bearing: temporarily delete the custom init(from:) so Swift synthesises one, confirm your new tests go red, then restore it. Do not include that deletion in the PR.
See CONTRIBUTING.md. No scanner needed.
Context
Two behaviours in
ScanDeckSettingsexist purely to stop a preference file from breaking the app, and both are documented as such in the source:init(from:)decodes field by field — "A settings file that fails to decode costs the operator every other preference in it".ScanDeckSettingsStore.load()falls back to.defaultviatry?— "an app that will not start because of a preference".Neither promise is checked. A future refactor to a synthesised
Codablewould silently delete both and every existing test would still pass.grep -rn 'ScanDeckSettingsStore' Tests/hits only four sites and all four merely construct the store to inject into the presentation model. EveryautoContinueSecondsassertion goes throughmodel.autoContinueSeconds, which tests the model's clamping, not the decoder.What to change
New file
Tests/ScanDeckCoreTests/ScanDeckSettingsTests.swift, usingInMemoryScanDeckSettingsStorage— neverUserDefaultsScanDeckSettingsStorage(), which is the production default and would corrupt the operator's real preferences.Cases worth writing:
preferredScannerNamedecodes, andautoContinueSecondsfalls back to its default..defaultfromload()rather than throwing.save→loadround trip preserves both fields.Use Swift Testing, not XCTest.
How to verify
A good check that the tests are load-bearing: temporarily delete the custom
init(from:)so Swift synthesises one, confirm your new tests go red, then restore it. Do not include that deletion in the PR.See CONTRIBUTING.md. No scanner needed.