|
| 1 | +// swiftlint:disable file_length type_body_length |
| 2 | + |
1 | 3 | @_spi(Private) @testable import Sentry |
2 | 4 | @_spi(Private) @testable import SentryTestUtils |
3 | 5 | import XCTest |
@@ -279,4 +281,147 @@ class TestInfoPlistWrapperTests: XCTestCase { |
279 | 281 | XCTAssertFalse(result2, "Should return false for key2") |
280 | 282 | XCTAssertNil(error2, "Should not set error for key2") |
281 | 283 | } |
| 284 | + |
| 285 | + // MARK: - getAppValueDictionary(for:) |
| 286 | + |
| 287 | + func testGetAppValueDictionary_withoutMockedValue_shouldFail() throws { |
| 288 | + // -- Arrange -- |
| 289 | + let sut = TestInfoPlistWrapper() |
| 290 | + // Don't mock any value for this key |
| 291 | + |
| 292 | + // -- Act & Assert -- |
| 293 | + XCTExpectFailure("We are expecting a failure when accessing an unmocked key, as it indicates the test setup is incomplete") |
| 294 | + _ = try sut.getAppValueDictionary(for: "unmockedKey") |
| 295 | + } |
| 296 | + |
| 297 | + func testGetAppValueDictionary_withMockedValue_withSingleInvocations_shouldReturnMockedValue() throws { |
| 298 | + // -- Arrange -- |
| 299 | + let sut = TestInfoPlistWrapper() |
| 300 | + let expectedDict = ["key1": "value1", "key2": 123] as [String: Any] |
| 301 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "dictKey", value: expectedDict) |
| 302 | + |
| 303 | + // -- Act -- |
| 304 | + let result = try sut.getAppValueDictionary(for: "dictKey") |
| 305 | + |
| 306 | + // -- Assert -- |
| 307 | + XCTAssertEqual(result["key1"] as? String, "value1", "Should return the mocked dictionary") |
| 308 | + XCTAssertEqual(result["key2"] as? Int, 123, "Should return the mocked dictionary") |
| 309 | + } |
| 310 | + |
| 311 | + func testGetAppValueDictionary_withMockedValue_withMultipleInvocations_shouldReturnSameValue() throws { |
| 312 | + // -- Arrange -- |
| 313 | + let sut = TestInfoPlistWrapper() |
| 314 | + let expectedDict = ["test": "value"] as [String: Any] |
| 315 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key1", value: expectedDict) |
| 316 | + |
| 317 | + // -- Act -- |
| 318 | + let result1 = try sut.getAppValueDictionary(for: "key1") |
| 319 | + let result2 = try sut.getAppValueDictionary(for: "key1") |
| 320 | + |
| 321 | + // -- Assert -- |
| 322 | + XCTAssertEqual(result1["test"] as? String, "value", "First invocation should return mocked value") |
| 323 | + XCTAssertEqual(result2["test"] as? String, "value", "Second invocation should return same mocked value") |
| 324 | + } |
| 325 | + |
| 326 | + func testGetAppValueDictionary_shouldRecordInvocations() throws { |
| 327 | + // -- Arrange -- |
| 328 | + let sut = TestInfoPlistWrapper() |
| 329 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key1", value: ["a": 1]) |
| 330 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key2", value: ["b": 2]) |
| 331 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key3", value: ["c": 3]) |
| 332 | + |
| 333 | + // -- Act -- |
| 334 | + _ = try sut.getAppValueDictionary(for: "key1") |
| 335 | + _ = try sut.getAppValueDictionary(for: "key2") |
| 336 | + _ = try sut.getAppValueDictionary(for: "key3") |
| 337 | + |
| 338 | + // -- Assert -- |
| 339 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.count, 3, "Should record all three invocations") |
| 340 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.invocations.element(at: 0), "key1", "First invocation should be for key1") |
| 341 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.invocations.element(at: 1), "key2", "Second invocation should be for key2") |
| 342 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.invocations.element(at: 2), "key3", "Third invocation should be for key3") |
| 343 | + } |
| 344 | + |
| 345 | + func testGetAppValueDictionary_withDifferentKeys_shouldReturnDifferentValues() throws { |
| 346 | + // -- Arrange -- |
| 347 | + let sut = TestInfoPlistWrapper() |
| 348 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key1", value: ["value": "one"]) |
| 349 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key2", value: ["value": "two"]) |
| 350 | + |
| 351 | + // -- Act -- |
| 352 | + let result1 = try sut.getAppValueDictionary(for: "key1") |
| 353 | + let result2 = try sut.getAppValueDictionary(for: "key2") |
| 354 | + |
| 355 | + // -- Assert -- |
| 356 | + XCTAssertEqual(result1["value"] as? String, "one", "Should return 'one' for key1") |
| 357 | + XCTAssertEqual(result2["value"] as? String, "two", "Should return 'two' for key2") |
| 358 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.count, 2, "Should record both invocations") |
| 359 | + } |
| 360 | + |
| 361 | + func testGetAppValueDictionary_withFailureResult_shouldThrowError() { |
| 362 | + // -- Arrange -- |
| 363 | + let sut = TestInfoPlistWrapper() |
| 364 | + sut.mockGetAppValueDictionaryThrowError(forKey: "key", error: SentryInfoPlistError.keyNotFound(key: "testKey")) |
| 365 | + |
| 366 | + // -- Act & Assert -- |
| 367 | + XCTAssertThrowsError(try sut.getAppValueDictionary(for: "key")) { error in |
| 368 | + guard case SentryInfoPlistError.keyNotFound(let key) = error else { |
| 369 | + XCTFail("Expected SentryInfoPlistError.keyNotFound, got \(error)") |
| 370 | + return |
| 371 | + } |
| 372 | + XCTAssertEqual(key, "testKey", "Error should contain the expected key") |
| 373 | + } |
| 374 | + } |
| 375 | + |
| 376 | + func testGetAppValueDictionary_withDifferentErrorTypes_shouldThrowCorrectError() { |
| 377 | + // -- Arrange -- |
| 378 | + let sut = TestInfoPlistWrapper() |
| 379 | + |
| 380 | + // Test mainInfoPlistNotFound |
| 381 | + sut.mockGetAppValueDictionaryThrowError(forKey: "key1", error: SentryInfoPlistError.mainInfoPlistNotFound) |
| 382 | + XCTAssertThrowsError(try sut.getAppValueDictionary(for: "key1")) { error in |
| 383 | + guard case SentryInfoPlistError.mainInfoPlistNotFound = error else { |
| 384 | + XCTFail("Expected SentryInfoPlistError.mainInfoPlistNotFound, got \(error)") |
| 385 | + return |
| 386 | + } |
| 387 | + } |
| 388 | + |
| 389 | + // Test unableToCastValue |
| 390 | + sut.mockGetAppValueDictionaryThrowError(forKey: "key2", error: SentryInfoPlistError.unableToCastValue(key: "castKey", value: "not a dict", type: [String: Any].self)) |
| 391 | + XCTAssertThrowsError(try sut.getAppValueDictionary(for: "key2")) { error in |
| 392 | + guard case SentryInfoPlistError.unableToCastValue(let key, let value, let type) = error else { |
| 393 | + XCTFail("Expected SentryInfoPlistError.unableToCastValue, got \(error)") |
| 394 | + return |
| 395 | + } |
| 396 | + XCTAssertEqual(key, "castKey", "Error should contain the correct key") |
| 397 | + XCTAssertEqual(value as? String, "not a dict", "Error should contain the correct value") |
| 398 | + XCTAssertTrue(type == [String: Any].self, "Error should contain the correct type") |
| 399 | + } |
| 400 | + } |
| 401 | + |
| 402 | + func testGetAppValueDictionary_afterThrowingError_shouldRecordInvocation() { |
| 403 | + // -- Arrange -- |
| 404 | + let sut = TestInfoPlistWrapper() |
| 405 | + sut.mockGetAppValueDictionaryThrowError(forKey: "key1", error: SentryInfoPlistError.keyNotFound(key: "testKey")) |
| 406 | + |
| 407 | + // -- Act -- |
| 408 | + _ = try? sut.getAppValueDictionary(for: "key1") |
| 409 | + |
| 410 | + // -- Assert -- |
| 411 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.count, 1, "Should record invocation even when throwing error") |
| 412 | + XCTAssertEqual(sut.getAppValueDictionaryInvocations.invocations.element(at: 0), "key1", "Should record the correct key") |
| 413 | + } |
| 414 | + |
| 415 | + func testGetAppValueDictionary_withEmptyDictionary_shouldReturnEmptyDictionary() throws { |
| 416 | + // -- Arrange -- |
| 417 | + let sut = TestInfoPlistWrapper() |
| 418 | + sut.mockGetAppValueDictionaryReturnValue(forKey: "key", value: [:]) |
| 419 | + |
| 420 | + // -- Act -- |
| 421 | + let result = try sut.getAppValueDictionary(for: "key") |
| 422 | + |
| 423 | + // -- Assert -- |
| 424 | + XCTAssertTrue(result.isEmpty, "Should return empty dictionary when mocked with empty dictionary") |
| 425 | + } |
282 | 426 | } |
| 427 | +// swiftlint:enable file_length type_body_length |
0 commit comments