* fix(network): log ignored GULMutableDictionary writes and document nil handling
Follow-up to the nil-key fix in #249.
- Log a warning (I-NET902000 for a nil key, I-NET902001 for a nil object)
when a write is ignored. Silently dropping the write hid the caller's bug;
the log keeps it visible without crashing.
- Mark the object parameter of -setObject:forKeyedSubscript: as nullable. A
nil object removes the key, as with NSMutableDictionary, and the tests rely
on this. It also lets Swift callers write `dict[key] = nil`.
- Document the nil handling in the header.
- Make testNilObjectIsIgnored check that an existing entry is kept, and pass
nil directly in testKeyedNilObjectRemovesKey.
* fix(network): move GULMutableDictionary log codes to 903xxx
I-NET902000-I-NET902006 are already used by GULReachabilityMessageCode, so
the new GULMutableDictionary warnings collided with reachability messages.
Use 903000/903001, which are unused in GoogleUtilities and
firebase-ios-sdk, and note the reserved reachability range next to the
enum.
* add more nil key tests
* fix(network): return nil early for nil keys in GULMutableDictionary getters
NSDictionary happens to return nil for a nil key, but this is not
documented. Return early from -objectForKey: and
-objectForKeyedSubscript: so the behavior does not depend on Foundation
and matches the nil-key guards on the write paths.
- Document the nil-key behavior of both getters in the header.
- Add tests that a nil-key lookup returns nil when the dictionary has
entries.
* test(network): add defensive GULMutableDictionary tests
- Check that -dictionary returns a snapshot that later writes don't change.
- Split the nil-key write test into one test per write path so a failure
names the method that caused it, and cover `dict[nil] = nil`.
- Cover removing a missing key, -removeAllObjects on an empty dictionary,
and -description.
* changelog and spec
* test(network): assert empty precondition in testRemoveAllWhenEmpty
* test(network): verify setup in GULMutableDictionary tests
Several tests could pass even if their setup silently failed. Check that
the setup took effect:
- testDictionaryReturnsSnapshot: the later writes changed the live
dictionary, so the snapshot assertions are meaningful.
- testKeyedNilObjectRemovesKey: the entry exists before it is removed.
- testObjectForNilKey(KeyedSubscript): the entry exists, so the tests
show a nil key does not match it.
* fix(network): mark GULMutableDictionary getters as returning nullable
objectForKey: and objectForKeyedSubscript: are documented to return nil for a missing or nil key, but were declared non-null, so Swift imported objectForKey(_:) as Any. Declare both as nullable id so the signatures match the documented behavior. Swift callers of objectForKey(_:) now get Any?; the subscript already read as Any? because its setter is nullable.
* test(network): add GULMutableDictionary concurrent access stress test
GULMutableDictionary is documented as providing atomic accessors and
mutators and is shared across threads by GULNetwork and the app delegate
swizzlers, but no test exercised it concurrently. Mix reads, writes,
removes, and nil-key calls across threads with dispatch_apply and check
that the final state is consistent.
Passed 200 repeated runs and a Thread Sanitizer run on the iOS simulator
with no reports.
---------
Co-authored-by: Nick Cooke <nickcooke@google.com>
* test: migrate away from OCMock
Replace dynamic OCMock mocks with handwritten fake classes across the test suite to improve Swift interoperability, address concurrency issues, and reduce test brittleness. Removed OCMock from podspec and SPM dependencies.
* gemfile
* Remove other files and deps
* Apply suggestion from @ncooke3
* Apply suggestion from @ncooke3
* [v8] Replace read keychain API with completion handler based API (#182)
* [v8] Replace write keychain API with completion handler based API (#183)
* [v8] Replace remove keychain API with completion handler based API (#184)
* [v8] Replace remove keychain API with completion handler based API
* Update GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m
* [v8] Fix tests, docs, and imports following `GULKeychainStorage` API changes (#185)
* [v8] Remove Promises API and dependency specifications (#186)
* [v8] Remove Promises API and dependency specifications
* Remove other header
* [v8] Add changelog for removal of Promises dependency
* [v8] Remove extraneous parameter from removeObject API (#188)
* [Infra] Setup third_party dir. structure
* Alt. approach with third_party dir at root
* Undo accidental target name change
* Fix remaining accidental changes
* Style
* Add import
* Fix syntax error in podspec
* Style, again
* Remove maybe? unneeded import and change order
* Fix warning
* Replace Google copyright in .h and .m
* Rename references from 'third_party/Environment' to 'third_party/IsAppEncrypted'
* Actually rename 'third_party/Environment/ -> third_party/IsAppEncrypted/'
* Add back void
* Remove extra text from LICENSE
* [Release] Update CHANGELOGs for 7.11.4 release
* [Release] Update podspec for 7.11.4 release
* Change punctuation order to be consistent with out entries
* GULHeartbeatDateStorage: use dispatch queue instead of NSFileCoordinator for synchronization
* Concurrency tests
* Adjust concurrency tests
* style
* Use @synchronized(self.class) instead of a dispatch queue
* Fix "unused variable" warnings
* Changelog
* Comment
* Update podspec version
* GULHeartbeatDateStorageTest: Cleanup before testing as well
* Replace expectations with dispatch_barrier_sync to workaround Catalyst test app issue
* style
* Introduce UserDefaults based heartbeat storage.
This can be used on tvOS without fear of losing data between launches.
Clients will need to instantiate the class of their choice, then can use the
`GULHeartbeatDateStorable` protocol if they want to mix and match.
* Fix PR number in CHANGELOG
* Style.sh
* Bump version in podspec.
* Renamed files appropriately
* Copyright fixes