Commit Graph
61 Commits
Author SHA1 Message Date
Cesar de la VegaandRevenueCat Git Bot 9b7313e400 run-test-ios-15 in xcode 15 to fix incompatibilities with emergetools (#4319)
Co-authored-by: RevenueCat Git Bot <72824662+RCGitBot@users.noreply.github.com>
2024-12-05 19:40:29 +01:00
Mark Villacampa 6f8e53ac40 Fix Xcode 16 warnings (#4334)
When compiling with Xcode 16, we started throwing a bunch of new warnings. Here's a list and explanation of each:

- The most common one was needing to explicitly restate the @unchecked Sendable conformance from a parent class.
- There were a couple switches where a new entry was added in tvOS but only for iOS 18, and needed to add it to make it exhaustive.
- There we a couple of places where we were adding a protocol conformance to a class from a different module e.g. extension DispatchTimeInterval: Comparable. This is considered unsafe now because the owners of the module could add the conformance later. Solved by removing the conformance which wasn't being used widely in the codebase, only in tests.
- Finally there was a class where we were capturing SKRequest and SKProductsRequest instances in a sendable block, but only to either log something, or use them as dictionary key, so I just made the classes Sendable (with the new @retroactice attribute because they belong to a different module)
2024-10-02 11:53:45 +02:00
Josh Holtz 26eed6c80a Fix failing all-tests and retry more flaky tests (#4188)
## Motivation

- Compile errors in Xcode 15 with iOS 16
- Flaky tests

## Description

### iOS 16 fixes

The following things aren't available:

- `@available(visionOS)` 
- `.topBarTrailing` (need to use `.navigationBarTrailing`)
- Fix issues with `Locale(identifier: "")` now returning `en` but ONLY
on iOS 16 in Xcode 15
  - iOS 17 returns the expected `nil` in Xcode 15
- There was a test using `#if swift` that was now being run by iOS 16
tests that needed an additional
`AvailabilityChecks.iOS17APIAvailableOrSkipTest()`

### Flaky tests fixes

Using new `scan_with_flaky_test_retries` action from in
`fastlane-plugin-revenuecat_internal`

- Replaces the `retry_failed_tests` lane that did a similar thing
- Removed a bunch of duplicated steps in the `.circle/config.yml` that
needed to run the `retry_failed_tests`
- `scan_with_flaky_test_retries` is now used in:
  - `test_ios`
  - `test_tvos`
  - `test_watchos`
  - `backend_integration_tests`

### Carthage tests timing out

The carthage installation tests timed out pretty regularly. They will
now use the large resource class (where everything else uses the medium)
2024-08-20 07:44:18 -05:00
Will Taylor a4055375f6 retry requests with HTTP status 429 2024-07-23 12:41:16 -05:00
NachoSoto 2bcd0ce328 5.0.0 changes: support SK2 by default 2024-07-01 14:37:21 -05:00
NachoSoto 6e9840062f Paywalls: fix finding locales with different regions (#3633)
This was a regression introduced by #3605.

### Example:

Consider a paywall configuration with these locales: `en_US`, `de_DE`.
Running on a device with locale `en_IN` for example.

Before #3605, `PaywallData.localizedConfiguration` would have returned
the `en_US` localization. However, that change made it so that it could
no longer find a matching localization with a different region.

This fix improves the locale lookup so that if it doesn't find a
matching localization with both language AND region, it then tries to
look it up with only the language, before falling back to the default
localization.
2024-02-05 15:26:03 -08:00
NachoSoto 7a23d5ba4d Expanded EnsureNonEmptyArrayDecodable to EnsureNonEmptyCollectionDecodable (#3002) 2023-08-14 07:35:41 -07:00
NachoSoto 04ef06ed44 @EnsureNonEmptyArrayDecodable (#2831) 2023-07-18 06:12:41 -07:00
NachoSoto 8483c29f47 New @NonEmptyStringDecodable (#2819)
This allows decorating a `String` property in a `Decodable` type so it
ensures it gets converted to `nil` if it's empty.
It will be used for `PaywallData`.
2023-07-14 15:00:12 -07:00
NachoSoto 4a0372bbf7 Replaced FatalErrorUtil with Nimble (#2802) 2023-07-13 05:28:58 -07:00
NachoSoto c5552fa453 IgnoreDecodeErrors: log decoding error (#2778) 2023-07-12 06:35:54 -07:00
NachoSoto b798114567 Refactor: extracted Collection.subscript(safe:) (#2779)
This is useful to have in extensions and not just in this test.
2023-07-11 10:22:19 -07:00
NachoSoto 3da1c50925 HTTPRequest.Path: escape appUserID (#2747)
We were escaping users for every (hopefully) request. This refactor
moves that responsibility to the path creation in `HTTPRequest.Path` to
ensure it's done consistently.

Additionally, this is required so that `SigningTests` produce a
consistent path (see #2746).
2023-07-05 15:41:51 -07:00
NachoSoto 26a33fc44c Add UInt32(littleEndian32Bits:) and UInt32.littleEndianData (#2713) 2023-06-27 04:54:54 -07:00
NachoSoto ed8d79dfdd Add Data.sha1 (#2696)
This also refactors the implementation to be able to share the same
code.

This algorithm will be used for some of the components in the new
signatures.
2023-06-23 10:45:57 -07:00
NachoSoto 0cadce9fb3 Add Sequence<AdditiveArithmetic>.sum() (#2694) 2023-06-23 07:35:03 -07:00
NachoSoto 1dc19f6750 Refactored Data.asString implementation (#2695) 2023-06-23 07:31:55 -07:00
NachoSoto f05fd88214 Diagnostics: new FileHandler for abstracting file operations (#2673)
Implemented as an `actor` to easily synchronize operations on a file.

Simple interface:
![Screenshot 2023-06-16 at 16 45
14](https://github.com/RevenueCat/purchases-ios/assets/685609/2f4850a3-f915-4330-a5e2-3abf9b37fb54)
2023-06-22 13:02:34 -07:00
NachoSoto 6d60af2c42 Xcode 15: handle Locale.currencyCode deprecation (#2680) 2023-06-22 06:23:32 -07:00
NachoSoto 9494f2e4ca Changed tests to work around URL decoding differences in iOS 17 (#2605)
The "invalid" test URLs we were using are no longer invalid on iOS 17.
This fixes those tests by using an `Int` instead of a `String`.

<img width="775" alt="image"
src="https://github.com/RevenueCat/purchases-ios/assets/685609/3ef5ec23-b17d-4ac1-9e4e-4dc48c97f5a9">
2023-06-09 09:47:17 -07:00
NachoSoto 094e8f2aad Extracted and tested AsyncSequence.extractValues (#2538) 2023-05-25 07:14:58 -07:00
NachoSoto 789a0e5e4d PurchasedProductsFetcher: cache current entitlements (#2507)
To optimize potentially computing offline `CustomerInfo`, this caches
what's likely the most expensive part.
2023-05-19 18:08:03 -07:00
NachoSoto 8b778b54d0 Tests: grouped all Matchers into one file (#2497)
Just a small refactor. I needed some of these matchers in a new test,
and realized we could reuse them in other places too.
2023-05-17 12:43:14 -04:00
NachoSoto 7b3b03d2b3 Xcode 14.3: fixed compilation errors (#2399)
See also #2397.
Xcode 14.3 introduced the following error:
> Heterogeneous collection literal could only be inferred to '[String :
Any]'; add explicit type annotation if this is intentional

### Changes:
- Added explicit types to fix this new error
- Removed unnecessary `@preconcurrency` imports
- Added new `CustomerInfo.emptyInfo` to reduce duplication of same fake
`CustomerInfo` creation
2023-04-11 08:55:21 -07:00
NachoSoto d9a755f695 @DefaultDecodable.Now: fixed flaky test (#2374) 2023-03-24 15:49:54 -07:00
NachoSoto 012a7a0b9d Added @DefaultDecodable.Now (#2372) 2023-03-24 07:41:43 -07:00
NachoSoto b495540308 Offline Entitlements: store ProductEntitlementMapping in cache (#2355)
## Changes:
- `DeviceCache` support for caching `ProductsEntitlementsResponse` as
well as "last updated" date
- Added `JSONEncoder.encode` helper matching `JSONDecoder.decode`
version, with an optional `logErrors` parameter
- `OfferingsManager. updateProductsEntitlementsCacheIfStale`
- `Purchases.updateAllCaches` also updates this new cache
- Added `OfferingsManager` / `DeviceCache` / `Purchases` tests
- Integration test for fetching mapping
2023-03-23 13:30:19 -07:00
NachoSoto d4ecc7b298 DispatchTimeInterval & Date: avoid 32-bit overflows, fix watchOS crashes (#2342)
Fixes #2338, [SDKONCALL-237], [SDK-2974].

`Int` is actually 32 bits in 32-bit platforms, like `watchOS` still is
(sort of).
This fixes 2 potential `Int` overflows: `Date.millisecondsSince1970` and
`DispatchTimeInterval` arithmetic using `nanoseconds`.

See also #2340.

[SDKONCALL-237]:
https://revenuecats.atlassian.net/browse/SDKONCALL-237?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2023-03-16 13:24:16 -07:00
NachoSoto da9ba397a3 Update CustomerInfo.requestDate from 304 responses (#2310)
### Purpose:

This is a prerequisite for #2288. The new grace period means that if we
didn't update the date from the cached responses, entitlements would
become stale and expired after 3 days.

### Changes:
- Added `HTTPResponseBody.copy(with newRequestDate:)` to be able to
modify responses from the header request date
- `CustomerInfo` implements this method to modify its request date
- Added `HTTPResponse.requestDate` to be able to keep track of the
request date from the server
- Added `VerificationResult.from(cache:response:)` to determine the most
restrictive verification result based on what's cached or checked from a
response
- Added `HTTPResponse.copy(with:)` to modify the verification result of
a response using the previous method
- `HTTPClient` now uses the most restrictive verification result
- `HTTPClient` updates request date from server responses or cached
responses (unless verification failed). This was the missing piece for
#2288.

### Tests:
- Verify that `ETagManager` does not use an ETag if verification was
previously not enabled
- Verify that `ETagManager` returns the request date from the server
when returning a cached response
- Verify that `HTTPClient` updates the request date from the server or
from a cached response
- Verify that `HTTPClient` does not update request date if verification
failed
- Tests for `HTTPResponse` request date parsing
- Test for `CustomerInfoResponseHandler` updating request date
- Tests for `CustomerInfo.copy(with newRequestDate:)`


### Other smaller changes:
- Moved `CustomerInfo.asData()` into `Encodable.asJSONEncodedData()`
- Renamed `requestTime` to `requestDate` everywhere for consistency
2023-03-01 09:24:32 -08:00
NachoSoto 88a78411f6 HTTPClient: added support for sending X-Nonce (#2214)
Fixes [CSDK-631].


[CSDK-631]:
https://revenuecats.atlassian.net/browse/CSDK-631?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2023-02-08 09:05:20 -08:00
NachoSoto e4bbd0528b ReceiptFetcher: refactored implementation to log error when failing to fetch receipt (#2202) 2023-01-16 07:43:34 -08:00
NachoSoto 9a289e554f PostReceiptDataOperation: replaced receipt base64 with hash for cache key (#2199)
Should fix #2198 and [SDKONCALL-200]. This is a big performance
optimization in time and memory, as we no longer need to convert the
entire receipt to `base64` and concatenate it to the string, which is
what was likely causing #2198.
This now uses `Data.hashString`, which avoids any data copies and
efficiently creates a hash with the receipt content.

Apart from the new tests for this property,
`BackendPostReceiptDataTests.testDoesntCacheForDifferentReceipts`
ensures that different receipts have different cache keys, and therefore
this new implementation still avoids collisions (other than the
extremely unlikely hash collisions).


[SDKONCALL-200]:
https://revenuecats.atlassian.net/browse/SDKONCALL-200?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2023-01-12 11:48:32 -08:00
NachoSotoandCesar de la Vega bae4a00408 Added Dictionary.merge (#2190)
This simplifies the `+=` implementation by avoiding an intermediate
dictionary, and allows a simpler way of merging dictionaries.

Will be used in #2174.

Co-authored-by: Cesar de la Vega <cesarvegaro@gmail.com>
2022-12-27 09:47:10 -08:00
NachoSoto 47143a84f4 Result.init(catching:) with async method (#2060)
I ended up not using this in my recent PR but it's a useful overload.
2022-11-23 11:22:17 -06:00
NachoSoto 76956ba3f3 NSData+RCExtensionsTests: improved errors (#2043)
I was adding a temporary test to verify a receipt, and made these better
to help debugging.

Mainly because I had to look at this failing code to realize that the
new receipt needed to be `.txt` (since Xcode doesn't show extensions
anymore), so I added that to the error messages.
2022-11-21 12:58:39 -08:00
NachoSoto 217fe82409 Async.call: added non-throwing overload (#2006)
This will be used by an upcoming PR.
2022-11-07 12:40:12 -08:00
NachoSoto 96ff9ec5b0 Added Set + Set and Set += Set operators (#2013) 2022-10-31 16:20:41 -07:00
NachoSoto f06a8ce647 Created InternalAPI for "health" request (#1971) 2022-10-20 13:03:15 -05:00
NachoSoto b981e0fa4b Async.call method to convert completion-block call to async (#1969)
This simplifies calling completion-block APIs as `async`. The opposite
of what #1943 introduced.
2022-10-10 08:36:15 -07:00
NachoSoto 46ac7598fc Abstracted conversion from async to completion-block APIs (#1943)
Created `Async` with some shared methods that make this conversion
simpler in a type-safe way.

Helps turn this:
```swift
_ = Task<Void, Never> {
    do {
        completion(.success(try await f()))
    } catch {
        completion(.failure(ErrorUtils.error())
    }
}
```

Into this:
```swift
Async.call(with: completion) {
    try await f()
}
```
2022-09-28 08:40:59 -07:00
NachoSoto 5c01aa37dd Added Collection.onlyElement (#1857)
Simplifies the common pattern in tests:
```swift
expect(array).to(haveCount(1))
let element = try XCTUnwrap(array.first)
```

Into simply:
```swift
let element = try XCTUnwrap(array.onlyElement)
```
2022-08-22 16:00:39 -07:00
NachoSoto e2fb802c38 Added Dictionary.mapKeys and Dictionary.compactMapKeys (#1734)
Fixes [CSDK-105].

This came up in https://github.com/RevenueCat/purchases-ios/pull/1534#discussion_r891433648 and will simplify some of the code in #1727.
2022-06-27 11:43:50 -07:00
NachoSoto 7ca28477f4 Fixed ROT13.string thread-safety (#1686)
Fixes #1685.

### Description

Swift's `lazy` and `static` property initialization is always thread-safe. However, `key` was only created as an empty dictionary, and the evaluation of `ROT13.string`, which was the one initializing that data, wasn't isolated.
By creating `ROT13.key` inline, this ensures that the initialization is only done once in a thread-safe way.
2022-06-10 11:31:04 -07:00
NachoSoto 294212fed1 Result.init(value:error:): avoid creating error if value is provided (#1672)
Our implementation of `ErrorUtils.error(with:message:underlyingError:extraUserInfo:)` always calls `ErrorUtils.logErrorIfNeeded`, this means that even though the error wasn't actually used, it was being logged as if it had occurred.
By using `@autoclosure` we avoid this and instead create it lazily.

This incorrect logging lead to [CSDK-112], which won't be confusing anymore.

[CSDK-112]: https://revenuecats.atlassian.net/browse/CSDK-112?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2022-06-08 11:54:06 -07:00
NachoSoto 9679af3bc1 CustomerInfoDecodingTests: added test to check decoding invalid data behavior (#1659)
See also #1658.
This updates the behavior of `CustomerInfoResponse` decoding so that having invalid content inside of one of the structures fails more loudly instead of getting ignored.

For that, `@DefaultValue` no longer ignores errors, and instead `@IgnoreDecodeErrors` must be used.
For some of the values in `CustomerInfoResponse` this makes sense (like `Store`), but not for things like subscriptions where we would be losing data.
2022-06-07 16:56:04 -07:00
NachoSoto 9000b5f1de Removed LossyCollections (#1657)
See #1651.

Since that regression fix, we're no longer using it because it's not possible to make it decode dictionary keys without changing their case.
Therefore we can't ensure data isn't changed in the process.
2022-06-07 15:08:59 -07:00
NachoSoto 66fb1a1fb8 DefaultDecodable.EmptyDictionary: added new test to verify partial decoding failure behavior (#1658)
The new test checks the behavior that even if only part of the dictionary fails to decode, the whole dictionary becomes empty.
2022-06-07 09:45:51 -07:00
NachoSoto 7bb76a3892 PurchasesOrchestrator.purchase(sk2Product:promotionalOffer:): simplified implementation with new operator (#1602)
Both `return` statements where the same, the `else` was just providing a default value to `customerInfoIfSynced`.
Because `??` doesn't support an `async` function, we couldn't use that. By using this new operator we can simplify the implementation to a single `return` statement.
2022-05-26 14:58:39 -07:00
NachoSoto 0132b69a86 Added @IgnoreEncodable property wrapper (#1567)
This allows having properties in an `Encodable` type that won't be encoded.
This will be used to storing the `rawData` when decoding our types (see #1496).
2022-05-23 18:27:18 -07:00
NachoSoto a634e493f1 Added String.asData to avoid dealing with Data? (#1566)
Turns out `Data(string.utf8)` is a much simpler way of converting `String` to `Data` that doesn't lead to an `Optional`.
UTF-8 can represent all valid Unicode code points, so this was always safe, but now we know at compile time.

The reason the old variant returned an `Optional` is because it accepts other encodings like `.ascii` which might not be able to represent everything in the `String`.

This simplifies several parts of the code that were dealing with an error that was impossible.
2022-05-20 15:53:27 -07:00