diff --git a/CHANGELOG.md b/CHANGELOG.md index ec57d7e52d..fa2881ce10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,53 @@ x.y.z Release notes (yyyy-MM-dd) ============================================================= ### Enhancements -* Add `@ObservedSectionedResults.remove(atOffsets:section:)` which adds the ability to +* Add `@ObservedSectionedResults.remove(atOffsets:section:)` which adds the ability to remove a Realm Object when using `onDelete` on `ForEach` in a SwiftUI `List`. +* Add support for Xcode 16 beta 1 and fix some of the new warnings. Note that + this does not yet include full support for Swift 6 language mode + ([#8618](https://github.com/realm/realm-swift/pull/8618)). +* `Realm.asyncWrite()` and `Realm.asyncRefresh()` now use the new `#isolation` + feature to avoid sendability warnings when building with Xcode 16 + ([#8618](https://github.com/realm/realm-swift/pull/8618)). +* Include the originating client reset error message in errors reporting that + automatic client reset handling failed. ([Core #7761](https://github.com/realm/realm-core/pull/7761)) +* Improve the performance of insertion-heavy write transactions, particularly + when setting a large number of properties on each object created + ([Core #7734](https://github.com/realm/realm-core/pull/7734)). +* App now trims trailing slashes from the base url rather than producing + confusing 404 errors. ([Core #7791](https://github.com/realm/realm-core/pull/7791)). ### Fixed * Deleting a Realm Object used in a `@ObservedSectionedResults` collection in `SwiftUI` would cause a crash during the diff on the `View`. ([#8294](https://github.com/realm/realm-swift/issues/8294), since v10.29.0) +* Fix some client resets (such as migrating to flexible sync) potentially + failing if a new client reset condition (such as rolling back a flexible sync + migration) occurred before the first one completed. + ([Core #7542](https://github.com/realm/realm-core/pull/7542), since v10.40.0) +* The encryption code no longer behaves differently depending on the system + page size, which should entirely eliminate a recurring source of bugs related + to copying encrypted Realm files between platforms with different page sizes. + One known outstanding bug was ([RNET-1141](https://github.com/realm/realm-dotnet/issues/3592)), + where opening files on a system with a larger page size than the writing + system would attempt to read sections of the file which had never been + written to ([Core #7698](https://github.com/realm/realm-core/pull/7698)). +* There were several complicated scenarios which could result in stale reads + from encrypted files in multiprocess scenarios. These were very difficult to + hit and would typically lead to a crash, either due to an assertion failure + or DecryptionFailure being thrown ([Core #7698](https://github.com/realm/realm-core/pull/7698), since v10.38.0). +* Encrypted files have some benign data races where we can memcpy a block of + memory while another thread is writing to a limited range of it. It is + logically impossible to ever read from that range when this happens, but + Thread Sanitizer quite reasonably complains about this. We now perform a + slower operations when running with TSan which avoids this benign race + ([Core #7698](https://github.com/realm/realm-core/pull/7698)). +* `Realm.asyncOpen()` on a flexible sync Realm would sometimes fail to wait for + pending subscriptions to complete, resulting in it not actually waiting for + all data to be downloaded. ([Core #7720](https://github.com/realm/realm-core/issues/7720), + since flexible sync was introduced). +* `List.clear()` would hit an assertion failure when used on a + file originally created by a version of Realm older than v10.49.0. + ([Core #7771](https://github.com/realm/realm-core/issues/7771), since 10.49.0) @@ -15,10 +56,10 @@ x.y.z Release notes (yyyy-MM-dd) * APIs are backwards compatible with all previous releases in the 10.x.y series. * Carthage release for Swift is built with Xcode 15.4.0. * CocoaPods: 1.10 or later. -* Xcode: 15.1.0-15.4.0. +* Xcode: 15.1.0-16 beta ### Internal -* Upgraded realm-core from ? to ? +* Upgraded realm-core from v14.9.0 to 14.10.1 10.51.0 Release notes (2024-06-06) ============================================================= @@ -48,29 +89,29 @@ x.y.z Release notes (yyyy-MM-dd) ```swift realm.objects(MixedObject.self).where { $0.anyValue[0][0][1] == .double(76.54) } ``` - + The `.any` operator allows looking up in all keys or indexes. ```swift realm.objects(MixedObject.self).where { $0.anyValue["key"].any == .bool(false) } ``` -* Report the originating error that caused a client reset to occur. +* Report the originating error that caused a client reset to occur. ([Core #6154](https://github.com/realm/realm-core/issues/6154)) ### Fixed -* Accessing `App.currentUser` from within a notification produced by `App.switchToUser()` - (which includes notifications for a newly logged in user) would deadlock. +* Accessing `App.currentUser` from within a notification produced by `App.switchToUser()` + (which includes notifications for a newly logged in user) would deadlock. ([Core #7670](https://github.com/realm/realm-core/issues/7670), since v10.50.0). -* Inserting the same link to the same key in a dictionary more than once would incorrectly create - multiple backlinks to the object. This did not appear to cause any crashes later, but would - have affecting explicit backlink count queries and possibly notifications. +* Inserting the same link to the same key in a dictionary more than once would incorrectly create + multiple backlinks to the object. This did not appear to cause any crashes later, but would + have affecting explicit backlink count queries and possibly notifications. ([Core #7676](https://github.com/realm/realm-core/issues/7676), since v10.49.2). -* A non-streaming progress notifier would not immediately call its callback after registration. - Instead you would have to wait for a download message to be received to get your first +* A non-streaming progress notifier would not immediately call its callback after registration. + Instead you would have to wait for a download message to be received to get your first update - if you were already caught up when you registered the notifier you could end up waiting a - long time for the server to deliver a download that would call/expire your notifier + long time for the server to deliver a download that would call/expire your notifier ([Core #7627](https://github.com/realm/realm-core/issues/7627), since v10.50.0). -* After compacting, a file upgrade would be triggered. This could cause loss of data +* After compacting, a file upgrade would be triggered. This could cause loss of data if `deleteRealmIfMigrationNeeded` is set to true. ([Core #7747](https://github.com/realm/realm-core/issues/7747), since v10.49.0). diff --git a/Configuration/Base.xcconfig b/Configuration/Base.xcconfig index 3e63b83ddd..c7d905772d 100644 --- a/Configuration/Base.xcconfig +++ b/Configuration/Base.xcconfig @@ -59,17 +59,17 @@ HEADER_SEARCH_PATHS = $(inherited) core/include; CODE_SIGN_IDENTITY[sdk=iphone*] = iPhone Developer; CODE_SIGNING_REQUIRED[sdk=macosx] = NO; -IPHONEOS_DEPLOYMENT_TARGET_1400 = 11.0; IPHONEOS_DEPLOYMENT_TARGET_1500 = 12.0; +IPHONEOS_DEPLOYMENT_TARGET_1600 = 12.0; IPHONEOS_DEPLOYMENT_TARGET = $(IPHONEOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR)); -MACOSX_DEPLOYMENT_TARGET_1400 = 10.13; MACOSX_DEPLOYMENT_TARGET_1500 = 10.14; +MACOSX_DEPLOYMENT_TARGET_1600 = 10.14; MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR)); -WATCHOS_DEPLOYMENT_TARGET_1400 = 4.0; WATCHOS_DEPLOYMENT_TARGET_1500 = 4.0; +WATCHOS_DEPLOYMENT_TARGET_1600 = 4.0; WATCHOS_DEPLOYMENT_TARGET = $(WATCHOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR)); -TVOS_DEPLOYMENT_TARGET_1400 = 11.0; TVOS_DEPLOYMENT_TARGET_1500 = 12.0; +TVOS_DEPLOYMENT_TARGET_1600 = 12.0; TVOS_DEPLOYMENT_TARGET = $(TVOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR)); APPLICATION_EXTENSION_API_ONLY = YES; diff --git a/Package.swift b/Package.swift index 5753020257..d0c8373dc6 100644 --- a/Package.swift +++ b/Package.swift @@ -3,7 +3,7 @@ import PackageDescription import Foundation -let coreVersion = Version("14.9.0") +let coreVersion = Version("14.10.1") let cocoaVersion = Version("10.51.0") let cxxSettings: [CXXSetting] = [ diff --git a/Realm.podspec b/Realm.podspec index 5573c47505..9257063ca4 100644 --- a/Realm.podspec +++ b/Realm.podspec @@ -130,17 +130,17 @@ Pod::Spec.new do |s| 'OTHER_CPLUSPLUSFLAGS' => '-isystem "${PODS_ROOT}/Realm/include/core" -fvisibility-inlines-hidden', 'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/Realm/include" "${PODS_ROOT}/Realm/include/Realm"', - 'IPHONEOS_DEPLOYMENT_TARGET_1400' => '11.0', 'IPHONEOS_DEPLOYMENT_TARGET_1500' => '12.0', + 'IPHONEOS_DEPLOYMENT_TARGET_1600' => '12.0', 'IPHONEOS_DEPLOYMENT_TARGET' => '$(IPHONEOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'MACOSX_DEPLOYMENT_TARGET_1400' => '10.13', 'MACOSX_DEPLOYMENT_TARGET_1500' => '10.13', + 'MACOSX_DEPLOYMENT_TARGET_1600' => '10.13', 'MACOSX_DEPLOYMENT_TARGET' => '$(MACOSX_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'WATCHOS_DEPLOYMENT_TARGET_1400' => '4.0', 'WATCHOS_DEPLOYMENT_TARGET_1500' => '4.0', + 'WATCHOS_DEPLOYMENT_TARGET_1600' => '4.0', 'WATCHOS_DEPLOYMENT_TARGET' => '$(WATCHOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'TVOS_DEPLOYMENT_TARGET_1400' => '11.0', 'TVOS_DEPLOYMENT_TARGET_1500' => '12.0', + 'TVOS_DEPLOYMENT_TARGET_1600' => '12.0', 'TVOS_DEPLOYMENT_TARGET' => '$(TVOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', 'OTHER_LDFLAGS' => '"-Wl,-unexported_symbols_list,${PODS_ROOT}/Realm/Configuration/Realm/PrivateSymbols.txt"', diff --git a/Realm/ObjectServerTests/SwiftObjectServerTests.swift b/Realm/ObjectServerTests/SwiftObjectServerTests.swift index a70c336bd3..a4491715d3 100644 --- a/Realm/ObjectServerTests/SwiftObjectServerTests.swift +++ b/Realm/ObjectServerTests/SwiftObjectServerTests.swift @@ -571,7 +571,7 @@ class SwiftObjectServerTests: SwiftSyncTestCase { proxy.stop() } - class LocationOverrideTransport: RLMNetworkTransport { + class LocationOverrideTransport: RLMNetworkTransport, Sendable { let hostname: String let wsHostname: String init(hostname: String = "http://localhost:9090", wsHostname: String = "ws://invalid.com:9090") { diff --git a/Realm/RLMCollection.mm b/Realm/RLMCollection.mm index 416a82f808..380a9d1484 100644 --- a/Realm/RLMCollection.mm +++ b/Realm/RLMCollection.mm @@ -527,7 +527,7 @@ - (bool)invalidate { } RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:collection]; - RLMRealmConfiguration *config = realm.configuration; + RLMRealmConfiguration *config = realm.configurationSharingSchema; dispatch_async(queue, ^{ std::lock_guard lock(token->_mutex); if (!token->_realm) { diff --git a/Realm/RLMObjectBase.mm b/Realm/RLMObjectBase.mm index a31310fe43..0cc1b5a114 100644 --- a/Realm/RLMObjectBase.mm +++ b/Realm/RLMObjectBase.mm @@ -790,7 +790,7 @@ - (void)registrationComplete:(void (^)())completion { RLMThreadSafeReference *tsr = [RLMThreadSafeReference referenceWithThreadConfined:(id)obj]; auto token = [[RLMObjectNotificationToken alloc] init]; token->_realm = obj->_realm; - RLMRealmConfiguration *config = obj->_realm.configuration; + RLMRealmConfiguration *config = obj->_realm.configurationSharingSchema; dispatch_async(queue, ^{ @autoreleasepool { [token addNotificationBlock:block threadSafeReference:tsr config:config keyPaths:keyPaths queue:queue]; diff --git a/Realm/RLMObservation.mm b/Realm/RLMObservation.mm index c3e530e961..8a9adb14b2 100644 --- a/Realm/RLMObservation.mm +++ b/Realm/RLMObservation.mm @@ -341,7 +341,7 @@ void RLMClearTable(RLMClassInfo &objectSchema) { return; } - _group.set_cascade_notification_handler([=](realm::Group::CascadeNotification const& cs) { + _group.set_cascade_notification_handler([this](realm::Group::CascadeNotification const& cs) { cascadeNotification(cs); }); } diff --git a/Realm/RLMQueryUtil.hpp b/Realm/RLMQueryUtil.hpp index 12df76e67f..fe68e0793b 100644 --- a/Realm/RLMQueryUtil.hpp +++ b/Realm/RLMQueryUtil.hpp @@ -29,9 +29,6 @@ namespace realm { @class RLMObjectSchema, RLMProperty, RLMSchema, RLMSortDescriptor; class RLMClassInfo; -extern NSString * const RLMPropertiesComparisonTypeMismatchException; -extern NSString * const RLMUnsupportedTypesFoundInPropertyComparisonException; - realm::Query RLMPredicateToQuery(NSPredicate *predicate, RLMObjectSchema *objectSchema, RLMSchema *schema, realm::Group &group); diff --git a/Realm/RLMQueryUtil.mm b/Realm/RLMQueryUtil.mm index 4b33516430..b9957cf317 100644 --- a/Realm/RLMQueryUtil.mm +++ b/Realm/RLMQueryUtil.mm @@ -38,13 +38,9 @@ using namespace realm; +namespace { NSString * const RLMPropertiesComparisonTypeMismatchException = @"RLMPropertiesComparisonTypeMismatchException"; -NSString * const RLMUnsupportedTypesFoundInPropertyComparisonException = @"RLMUnsupportedTypesFoundInPropertyComparisonException"; - NSString * const RLMPropertiesComparisonTypeMismatchReason = @"Property type mismatch between %@ and %@"; -NSString * const RLMUnsupportedTypesFoundInPropertyComparisonReason = @"Comparison between %@ and %@"; - -namespace { // small helper to create the many exceptions thrown when parsing predicates [[gnu::cold]] [[noreturn]] diff --git a/Realm/RLMRealm.mm b/Realm/RLMRealm.mm index c5e177eb2c..316ff4f58d 100644 --- a/Realm/RLMRealm.mm +++ b/Realm/RLMRealm.mm @@ -596,6 +596,14 @@ - (RLMRealmConfiguration *)configuration { return configuration; } +- (RLMRealmConfiguration *)configurationSharingSchema { + RLMRealmConfiguration *configuration = [[RLMRealmConfiguration alloc] init]; + configuration.configRef = _realm->config(); + configuration.dynamic = _dynamic; + [configuration setCustomSchemaWithoutCopying:_schema]; + return configuration; +} + - (void)beginWriteTransaction { [self beginWriteTransactionWithError:nil]; } @@ -1076,7 +1084,7 @@ - (RLMRealm *)freeze { - (RLMRealm *)thaw { [self verifyThread]; - return self.isFrozen ? [RLMRealm realmWithConfiguration:self.configuration error:nil] : self; + return self.isFrozen ? [RLMRealm realmWithConfiguration:self.configurationSharingSchema error:nil] : self; } - (RLMRealm *)frozenCopy { diff --git a/Realm/RLMRealmUtil.mm b/Realm/RLMRealmUtil.mm index 2fad212f6e..ceb87fb967 100644 --- a/Realm/RLMRealmUtil.mm +++ b/Realm/RLMRealmUtil.mm @@ -234,7 +234,7 @@ @implementation RLMPinnedRealm { - (instancetype)initWithRealm:(RLMRealm *)realm { if (self = [super init]) { _pin = realm->_realm->duplicate(); - _configuration = realm.configuration; + _configuration = realm.configurationSharingSchema; } return self; } diff --git a/Realm/RLMRealm_Private.h b/Realm/RLMRealm_Private.h index d247de39bc..e2bfa264fc 100644 --- a/Realm/RLMRealm_Private.h +++ b/Realm/RLMRealm_Private.h @@ -65,6 +65,11 @@ FOUNDATION_EXTERN void RLMRealmSubscribeToAll(RLMRealm *); @property (nonatomic, readonly, nullable) id actor; @property (nonatomic, readonly) bool isFlexibleSync; +// `-configuration` does a deep copy of the schema as if the user mutates the +// RLMSchema in use by a RLMRealm things will break horribly. When we know that +// the configuration won't be exposed we can skip the copy. +- (RLMRealmConfiguration *)configurationSharingSchema NS_RETURNS_RETAINED; + + (void)resetRealmState; - (void)registerEnumerator:(RLMFastEnumerator *)enumerator; diff --git a/Realm/RLMResults.mm b/Realm/RLMResults.mm index 699eac7bf8..eac9566e7b 100644 --- a/Realm/RLMResults.mm +++ b/Realm/RLMResults.mm @@ -574,7 +574,7 @@ - (void)completionWithThreadSafeReference:(RLMThreadSafeReference * _Nullable)re confinedTo:(RLMScheduler *)confinement completion:(RLMResultsCompletionBlock)completion error:(NSError *_Nullable)error { - RLMRealmConfiguration *configuration = _realm.configuration; + RLMRealmConfiguration *configuration = _realm.configurationSharingSchema; [confinement invoke:^{ if (error) { return completion(nil, error); diff --git a/Realm/Swift/RLMSupport.swift b/Realm/Swift/RLMSupport.swift index ab3c840ab9..ab7544100c 100644 --- a/Realm/Swift/RLMSupport.swift +++ b/Realm/Swift/RLMSupport.swift @@ -66,7 +66,7 @@ extension RLMObject { } /// A protocol defining iterator support for RLMArray, RLMSet & RLMResults. -public protocol _RLMCollectionIterator { +public protocol _RLMCollectionIterator: Sequence { /** Returns a `RLMCollectionIterator` that yields successive elements in the collection. This enables support for sequence-style enumeration of `RLMObject` subclasses in Swift. @@ -97,10 +97,17 @@ extension _RLMDictionaryIterator where Self: RLMCollection { // Sequence conformance for RLMArray, RLMDictionary, RLMSet and RLMResults is provided by RLMCollection's // `makeIterator()` implementation. +#if compiler(<6.0) extension RLMArray: Sequence, _RLMCollectionIterator { } extension RLMDictionary: Sequence, _RLMDictionaryIterator {} extension RLMSet: Sequence, _RLMCollectionIterator {} extension RLMResults: Sequence, _RLMCollectionIterator {} +#else +extension RLMArray: @retroactive Sequence, _RLMCollectionIterator { } +extension RLMDictionary: @retroactive Sequence, _RLMDictionaryIterator {} +extension RLMSet: @retroactive Sequence, _RLMCollectionIterator {} +extension RLMResults: @retroactive Sequence, _RLMCollectionIterator {} +#endif /** This struct enables sequence-style enumeration for RLMObjects in Swift via `RLMCollection.makeIterator` diff --git a/Realm/TestUtils/include/RLMAssertions.h b/Realm/TestUtils/include/RLMAssertions.h index 9dee40ca01..ed92434766 100644 --- a/Realm/TestUtils/include/RLMAssertions.h +++ b/Realm/TestUtils/include/RLMAssertions.h @@ -115,7 +115,7 @@ FOUNDATION_EXTERN bool RLMHasCachedRealmForPath(NSString *path); #define RLMAssertThrowsWithCodeMatching(expression, expectedCode, ...) \ ({ \ NSException *exception = RLMAssertThrows(expression, __VA_ARGS__); \ - XCTAssertEqual([exception.userInfo[NSUnderlyingErrorKey] code], expectedCode, __VA_ARGS__); \ + XCTAssertEqual([(NSError *)exception.userInfo[NSUnderlyingErrorKey] code], expectedCode, __VA_ARGS__); \ }) #define RLMValidateError(error, errDomain, errCode, msg) do { \ diff --git a/Realm/Tests/EncryptionTests.mm b/Realm/Tests/EncryptionTests.mm index b4e2093fd2..889e8de429 100644 --- a/Realm/Tests/EncryptionTests.mm +++ b/Realm/Tests/EncryptionTests.mm @@ -88,7 +88,7 @@ - (void)testReopenWithWrongKeyThrows { NSData *key = RLMGenerateKey(); RLMAssertRealmExceptionContains([self realmWithKey:key], RLMErrorInvalidDatabase, - @"Failed to open Realm file at path '%@': Realm file decryption failed (Decryption failed: unable to decrypt after 0 seconds", + @"Failed to open Realm file at path '%@': Realm file decryption failed (Decryption failed: page 0 in file of size", RLMDefaultRealmURL().path); } @@ -100,7 +100,7 @@ - (void)testOpenUnencryptedWithKeyThrows { NSData *key = RLMGenerateKey(); RLMAssertRealmExceptionContains([self realmWithKey:key], RLMErrorInvalidDatabase, - @"Failed to open Realm file at path '%@': Realm file decryption failed (Decryption failed: failed to decrypt block 0 in file of size", + @"Failed to open Realm file at path '%@': Realm file decryption failed (Decryption failed: page 0 in file of size", RLMDefaultRealmURL().path); } diff --git a/Realm/Tests/SwiftUITestHostUITests/SwiftUITestHostUITests.swift b/Realm/Tests/SwiftUITestHostUITests/SwiftUITestHostUITests.swift index 3002fb0704..d14ba9525e 100644 --- a/Realm/Tests/SwiftUITestHostUITests/SwiftUITestHostUITests.swift +++ b/Realm/Tests/SwiftUITestHostUITests/SwiftUITestHostUITests.swift @@ -93,6 +93,12 @@ class SwiftUITests: XCTestCase { app.buttons["New List"].tap() XCTAssertTrue(app.navigationBars.staticTexts["New List"].waitForExistence(timeout: 1.0)) app.buttons["addReminder"].tap() + if #available(iOS 18, *) { + // Work around what appears to be a bug in SwiftUI in iOS 18 beta 1 + // where tapping the list entry doesn't navigate to ReminderView + // if there's only one list entry + app.buttons["addReminder"].tap() + } // type in a name if #available(iOS 16, *) { app.cells.element(boundBy: 0).tap() @@ -143,6 +149,10 @@ class SwiftUITests: XCTestCase { app.buttons.matching(identifier: "Delete").firstMatch.tap() } } + if #available(iOS 18, *) { + XCTAssertEqual(realm.objects(ReminderList.self).first!.reminders.count, 3) + delete() + } XCTAssertEqual(realm.objects(ReminderList.self).first!.reminders.count, 2) delete() XCTAssertEqual(realm.objects(ReminderList.self).first!.reminders.count, 1) @@ -419,7 +429,7 @@ class SwiftUITests: XCTestCase { // been inserted into the Realm. if #available(iOS 16, *) { let sectionHeader1 = app.collectionViews.children(matching: .cell).element(boundBy: 0) - XCTAssert(sectionHeader1.staticTexts["A"].exists) + XCTAssert(sectionHeader1.staticTexts["A"].waitForExistence(timeout: 1.0)) let cell0 = app.collectionViews.children(matching: .cell).element(boundBy: 1) XCTAssert(cell0.staticTexts["Another List"].exists) let sectionHeader2 = app.collectionViews.children(matching: .cell).element(boundBy: 2) @@ -520,7 +530,7 @@ class SwiftUITests: XCTestCase { // been inserted into the Realm. if #available(iOS 16, *) { let sectionHeader1 = app.collectionViews.children(matching: .cell).element(boundBy: 0) - XCTAssert(sectionHeader1.staticTexts["A"].exists) + XCTAssert(sectionHeader1.staticTexts["A"].waitForExistence(timeout: 1.0)) let cell0 = app.collectionViews.children(matching: .cell).element(boundBy: 1) XCTAssert(cell0.staticTexts["Another List"].exists) let sectionHeader2 = app.collectionViews.children(matching: .cell).element(boundBy: 2) diff --git a/RealmSwift.podspec b/RealmSwift.podspec index a3e6b97d2b..6fb153afac 100644 --- a/RealmSwift.podspec +++ b/RealmSwift.podspec @@ -33,17 +33,17 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { 'APPLICATION_EXTENSION_API_ONLY' => 'YES', - 'IPHONEOS_DEPLOYMENT_TARGET_1400' => '11.0', 'IPHONEOS_DEPLOYMENT_TARGET_1500' => '12.0', + 'IPHONEOS_DEPLOYMENT_TARGET_1600' => '12.0', 'IPHONEOS_DEPLOYMENT_TARGET' => '$(IPHONEOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'MACOSX_DEPLOYMENT_TARGET_1400' => '10.13', 'MACOSX_DEPLOYMENT_TARGET_1500' => '10.13', + 'MACOSX_DEPLOYMENT_TARGET_1600' => '10.13', 'MACOSX_DEPLOYMENT_TARGET' => '$(MACOSX_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'WATCHOS_DEPLOYMENT_TARGET_1400' => '4.0', 'WATCHOS_DEPLOYMENT_TARGET_1500' => '4.0', + 'WATCHOS_DEPLOYMENT_TARGET_1600' => '4.0', 'WATCHOS_DEPLOYMENT_TARGET' => '$(WATCHOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', - 'TVOS_DEPLOYMENT_TARGET_1400' => '11.0', 'TVOS_DEPLOYMENT_TARGET_1500' => '12.0', + 'TVOS_DEPLOYMENT_TARGET_1600' => '12.0', 'TVOS_DEPLOYMENT_TARGET' => '$(TVOS_DEPLOYMENT_TARGET_$(XCODE_VERSION_MAJOR))', } end diff --git a/RealmSwift/Aliases.swift b/RealmSwift/Aliases.swift index 24d72621e3..25cb6804f0 100644 --- a/RealmSwift/Aliases.swift +++ b/RealmSwift/Aliases.swift @@ -94,10 +94,8 @@ extension ObjectBase { let token = RLMObjectNotificationToken() token.observe(self, keyPaths: keyPaths) { object, names, oldValues, newValues, error in assert(error == nil) - assumeOnActorExecutor(actor) { actor in - block(actor, .init(object: object as? T, names: names, + actor.invokeIsolated(block, .init(object: object as? T, names: names, oldValues: oldValues, newValues: newValues)) - } } await withTaskCancellationHandler(operation: token.registrationComplete, onCancel: { token.invalidate() }) diff --git a/RealmSwift/App.swift b/RealmSwift/App.swift index 8acdca293b..b10f97d2bb 100644 --- a/RealmSwift/App.swift +++ b/RealmSwift/App.swift @@ -397,7 +397,7 @@ public struct AppPublisher: Publisher, @unchecked Sendable { // DispatchQueue } @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) -extension App: ObservableObject { +extension App { /// A publisher that emits Void each time the app changes. /// /// Despite the name, this actually emits *after* the app has changed. @@ -405,6 +405,11 @@ extension App: ObservableObject { return AppPublisher(self, scheduler: DispatchQueue.main) } } +#if compiler(>=6) +extension App: @retroactive ObservableObject {} +#else +extension App: ObservableObject {} +#endif @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) internal func promisify(_ fn: @escaping (@escaping @Sendable (Error?) -> Void) -> Void) -> Future { diff --git a/RealmSwift/Combine.swift b/RealmSwift/Combine.swift index 5b219efce2..4049597d45 100644 --- a/RealmSwift/Combine.swift +++ b/RealmSwift/Combine.swift @@ -612,7 +612,7 @@ extension Realm { // MARK: - Object @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) -extension Object: ObservableObject { +extension Object { /// A publisher that emits Void each time the object changes. /// /// Despite the name, this actually emits *after* the object has changed. @@ -621,7 +621,7 @@ extension Object: ObservableObject { } } @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) -extension EmbeddedObject: ObservableObject { +extension EmbeddedObject { /// A publisher that emits Void each time the object changes. /// /// Despite the name, this actually emits *after* the embedded object has changed. @@ -647,6 +647,18 @@ extension ObjectBase: RealmSubscribable { } } +#if compiler(>=6) +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension Object: @retroactive ObservableObject {} +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension EmbeddedObject: @retroactive ObservableObject {} +#else +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension Object: ObservableObject {} +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension EmbeddedObject: ObservableObject {} +#endif + // MARK: - List @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) @@ -927,7 +939,7 @@ public enum RealmPublishers { try? Realm(RLMRealm(configuration: config, queue: scheduler as? DispatchQueue)) } static private func realm(_ sourceRealm: Realm, _ scheduler: S) -> Realm? { - return realm(sourceRealm.rlmRealm.configuration, scheduler) + return realm(sourceRealm.rlmRealm.configurationSharingSchema(), scheduler) } /// A publisher which emits an asynchronously opened Realm. @@ -1288,7 +1300,7 @@ public enum RealmPublishers { private let scheduler: S internal init(_ upstream: Upstream, _ scheduler: S, _ realm: Realm) { - self.config = realm.rlmRealm.configuration + self.config = realm.rlmRealm.configurationSharingSchema() self.upstream = upstream self.scheduler = scheduler } @@ -1365,7 +1377,7 @@ public enum RealmPublishers { self.upstream .map { (obj: Output) -> Handover in guard let realm = obj.realm, !realm.isFrozen else { return .object(obj) } - return .tsr(ThreadSafeReference(to: obj), config: realm.rlmRealm.configuration) + return .tsr(ThreadSafeReference(to: obj), config: realm.rlmRealm.configurationSharingSchema()) } .receive(on: scheduler) .compactMap { (handover: Handover) -> Output? in diff --git a/RealmSwift/Error.swift b/RealmSwift/Error.swift index f9d8d9275e..5028edb100 100644 --- a/RealmSwift/Error.swift +++ b/RealmSwift/Error.swift @@ -48,7 +48,11 @@ extension Realm.Error { // MARK: Equatable +#if compiler(>=6) +extension Realm.Error: @retroactive Equatable {} +#else extension Realm.Error: Equatable {} +#endif // FIXME: we should not be defining this but it's a breaking change to remove /// Returns a Boolean indicating whether the errors are identical. diff --git a/RealmSwift/Impl/ObjcBridgeable.swift b/RealmSwift/Impl/ObjcBridgeable.swift index 8b17dba00a..5f1cfb6d5f 100644 --- a/RealmSwift/Impl/ObjcBridgeable.swift +++ b/RealmSwift/Impl/ObjcBridgeable.swift @@ -202,11 +202,16 @@ extension ResultsSection: BuiltInObjcBridgeable { } } -extension RLMSwiftCollectionBase: Equatable { +extension RLMSwiftCollectionBase { public static func == (lhs: RLMSwiftCollectionBase, rhs: RLMSwiftCollectionBase) -> Bool { return lhs.isEqual(rhs) } } +#if compiler(>=6) +extension RLMSwiftCollectionBase: @retroactive Equatable {} +#else +extension RLMSwiftCollectionBase: Equatable {} +#endif extension Projection: BuiltInObjcBridgeable { public static func _rlmFromObjc(_ value: Any) -> Self? { diff --git a/RealmSwift/Impl/RealmCollectionImpl.swift b/RealmSwift/Impl/RealmCollectionImpl.swift index 5957147b25..3249e1e38c 100644 --- a/RealmSwift/Impl/RealmCollectionImpl.swift +++ b/RealmSwift/Impl/RealmCollectionImpl.swift @@ -128,9 +128,7 @@ extension RealmCollectionImpl { ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } @@ -182,7 +180,7 @@ internal func with( let unchecked = Unchecked(wrappedValue: value) return try await actor.invoke { actor in if !Task.isCancelled { -#if swift(>=5.10) +#if swift(>=5.10) && compiler(<6) // As of Swift 5.10 the compiler incorrectly thinks that this // is an async hop even though the isolation context is // unchanged. This is fixed in 5.11. @@ -197,7 +195,7 @@ internal func with( } let tsr = ThreadSafeReference(to: value) - let config = Unchecked(wrappedValue: value.realm!.rlmRealm.configuration) + let config = Unchecked(wrappedValue: value.realm!.rlmRealm.configurationSharingSchema()) return try await actor.invoke { actor in if Task.isCancelled { return nil @@ -207,7 +205,7 @@ internal func with( guard let value = tsr.resolve(in: realm) else { return nil } -#if swift(>=5.10) +#if swift(>=5.10) && compiler(<6) // As above; this is safe but 5.10's sendability checking can't prove it // nonisolated(unsafe) can't be applied to a let in guard so we need // a second variable diff --git a/RealmSwift/Map.swift b/RealmSwift/Map.swift index 88274cefcd..4f5d48af25 100644 --- a/RealmSwift/Map.swift +++ b/RealmSwift/Map.swift @@ -607,9 +607,7 @@ public final class Map: RLMSwiftColle ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Projection.swift b/RealmSwift/Projection.swift index 60a4101765..73e3b42f82 100644 --- a/RealmSwift/Projection.swift +++ b/RealmSwift/Projection.swift @@ -536,9 +536,7 @@ extension ProjectionObservable { ) async -> NotificationToken { await with(self, on: actor) { actor, obj in obj.observe(keyPaths: keyPaths, on: nil) { (change: ObjectChange) in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Realm.swift b/RealmSwift/Realm.swift index c9a24fb133..5a5bed9b18 100644 --- a/RealmSwift/Realm.swift +++ b/RealmSwift/Realm.swift @@ -1270,6 +1270,7 @@ extension Realm { self = Realm(rlmRealm.wrappedValue) } +#if compiler(<6) /** Performs actions contained within the given block inside a write transaction. @@ -1324,14 +1325,16 @@ extension Realm { fatalError("asyncWrite() can only be called on main thread or actor-isolated Realms") } return try await withoutActuallyEscaping(block) { block in - try await asyncWrite(actor: actor, Unchecked(block)).wrappedValue + try await Self.asyncWrite(actor: actor, realm: Unchecked(rlmRealm), Unchecked(block)).wrappedValue } } - private func asyncWrite(actor: isolated any Actor, - _ block: Unchecked<(() throws -> Result)>) async throws + private static func asyncWrite(actor: isolated any Actor, + realm: Unchecked, + _ block: Unchecked<(() throws -> Result)>) async throws -> Unchecked { - let write = rlmRealm.beginAsyncWrite() + let realm = realm.wrappedValue + let write = realm.beginAsyncWrite() await withTaskCancellationHandler { await write.wait() } onCancel: { @@ -1343,12 +1346,12 @@ extension Realm { try Task.checkCancellation() ret = try block.wrappedValue() } catch { - if isInWriteTransaction { cancelWrite() } + if realm.inWriteTransaction { realm.cancelWriteTransaction() } throw error } - if isInWriteTransaction { - try await rlmRealm.commitAsyncWrite(withGrouping: false) + if realm.inWriteTransaction { + try await realm.commitAsyncWrite(withGrouping: false) } return Unchecked(ret) } @@ -1381,6 +1384,117 @@ extension Realm { task.complete(false) } } + +#else // compiler(<6) + + /** + Performs actions contained within the given block inside a write transaction. + + This function differs from synchronous ``write`` in that it suspends the + calling task while waiting for its turn to write rather than blocking the + thread. In addition, the actual i/o to write data to disk is done by a + background worker thread. For small writes, using this function on the + main thread may block the main thread for less time than manually + dispatching the write to a background thread. + + If the block throws an error, the transaction will be canceled and any + changes made before the error will be rolled back. + + Only one write transaction can be open at a time for each Realm file. Write + transactions cannot be nested, and trying to begin a write transaction on a + Realm which is already in a write transaction will throw an exception. + Calls to `write` from `Realm` instances for the same Realm file in other + threads or other processes will block until the current write transaction + completes or is cancelled. + + Before beginning the write transaction, `asyncWrite` updates the `Realm` + instance to the latest Realm version, as if `asyncRefresh()` had been called, + and generates notifications if applicable. This has no effect if the Realm + was already up to date. + + You can skip notifying specific notification blocks about the changes made + in this write transaction by passing in their associated notification + tokens. This is primarily useful when the write transaction is saving + changes already made in the UI and you do not want to have the notification + block attempt to re-apply the same changes. + + The tokens passed to this function must be for notifications for this Realm + which were added on the same actor as the write transaction is being + performed on. Notifications for different threads cannot be skipped using + this method. + + - parameter tokens: An array of notification tokens which were returned + from adding callbacks which you do not want to be + notified for the changes made in this write transaction. + + - parameter block: The block containing actions to perform. + - returns: The value returned from the block, if any. + + - throws: An `NSError` if the transaction could not be completed successfully. + `CancellationError` if the task is cancelled. + If `block` throws, the function throws the propagated `ErrorType` instead. + */ + @discardableResult + public func asyncWrite(_isolation actor: isolated any Actor = #isolation, _ block: (() throws -> Result)) async throws -> Result { + guard rlmRealm.actor != nil else { + fatalError("asyncWrite() can only be called on main thread or actor-isolated Realms") + } + let realm = rlmRealm + let write = realm.beginAsyncWrite() + await withTaskCancellationHandler { + await write.wait() + } onCancel: { + actor.invoke { write.complete(true) } + } + + let ret: Result + do { + try Task.checkCancellation() + ret = try block() + } catch { + if realm.inWriteTransaction { realm.cancelWriteTransaction() } + throw error + } + + if realm.inWriteTransaction { + let error = await withCheckedContinuation { continuation in + realm.commitAsyncWrite(withGrouping: false, completion: continuation.resume) + } + if let error { + throw error + } + } + return ret + } + + /** + Updates the Realm and outstanding objects managed by the Realm to point to + the most recent data and deliver any applicable notifications. + + This function should be used instead of synchronous ``refresh`` in async + functions, as it suspends the calling task (if required) rather than + blocking. + + - warning: This function is only supported for main thread and + actor-isolated Realms. + - returns: Whether there were any updates for the Realm. Note that `true` + may be returned even if no data actually changed. + */ + @discardableResult + public func asyncRefresh(_isolation: isolated any Actor = #isolation) async -> Bool { + guard rlmRealm.actor != nil else { + fatalError("asyncRefresh() can only be called on main thread or actor-isolated Realms") + } + guard let task = RLMRealmRefreshAsync(rlmRealm) else { + return false + } + return await withTaskCancellationHandler { + await task.wait() + } onCancel: { + task.complete(false) + } + } +#endif // compiler(<6) } @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) @@ -1459,6 +1573,12 @@ extension RLMAsyncDownloadTask: TaskWithCancellation {} @available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *) internal extension Actor { func verifier() -> (@Sendable () -> Void) { +#if compiler(>=5.10) + // This was made backdeployable in Xcode 15.3 + return { + self.preconditionIsolated() + } +#else // When possible use the official API for actor checking if #available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, *) { return { @@ -1472,6 +1592,7 @@ internal extension Actor { // from outside the actor when actor data race checking is enabled. let fn: () -> Void = { _ = self } return unsafeBitCast(fn, to: (@Sendable () -> Void).self) +#endif } // Asynchronously invoke the given block on the actor. This takes a diff --git a/RealmSwift/SectionedResults.swift b/RealmSwift/SectionedResults.swift index acbe569411..04cd203393 100644 --- a/RealmSwift/SectionedResults.swift +++ b/RealmSwift/SectionedResults.swift @@ -206,9 +206,7 @@ public extension RealmSectionedResult { ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Sync.swift b/RealmSwift/Sync.swift index b09f2e5e65..417d9805e0 100644 --- a/RealmSwift/Sync.swift +++ b/RealmSwift/Sync.swift @@ -1098,7 +1098,7 @@ public class UserPublisher: Publisher { } @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) -extension User: ObservableObject { +extension User { /// A publisher that emits Void each time the user changes. /// /// Despite the name, this actually emits *after* the user has changed. @@ -1107,6 +1107,14 @@ extension User: ObservableObject { } } +#if compiler(>=6) +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension User: @retroactive ObservableObject {} +#else +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension User: ObservableObject {} +#endif + public extension User { // NEXT-MAJOR: This function returns the incorrect type. It should be Document // rather than `[AnyHashable: Any]` diff --git a/RealmSwift/Tests/AnyRealmValueTests.swift b/RealmSwift/Tests/AnyRealmValueTests.swift index e66d91507f..cd7ee506f7 100644 --- a/RealmSwift/Tests/AnyRealmValueTests.swift +++ b/RealmSwift/Tests/AnyRealmValueTests.swift @@ -91,7 +91,7 @@ func doubleValue(_ value: AnyRealmValue) -> Double { } } -class AnyRealmValueTests: TestCase { +class AnyRealmValueTests: TestCase, @unchecked Sendable { func testAnyRealmValue() { let values = T.anyValues() let o = AnyRealmTypeObject() @@ -110,7 +110,7 @@ class AnyRealmValueTests: TestCase { XCTAssertEqual(o.anyValue.value, values[2]) } } -class AnyRealmValuePrimitiveTests: TestCase { +class AnyRealmValuePrimitiveTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Any Realm Value Tests") AnyRealmValueTests.defaultTestSuite.tests.forEach(suite.addTest) @@ -126,7 +126,7 @@ class AnyRealmValuePrimitiveTests: TestCase { } } -class AnyRealmValueObjectTests: TestCase { +class AnyRealmValueObjectTests: TestCase, @unchecked Sendable { func testObject() { let o = AnyRealmTypeObject() let so = SwiftStringObject() @@ -237,7 +237,7 @@ class AnyRealmValueObjectTests: TestCase { // MARK: - List tests -class AnyRealmValueListTestsBase: TestCase { +class AnyRealmValueListTestsBase: TestCase, @unchecked Sendable { var realm: Realm? var obj: ModernAllTypesObject! var array: List! @@ -257,7 +257,7 @@ class AnyRealmValueListTestsBase: TestCase } } -class AnyRealmValueListTests: AnyRealmValueListTestsBase { +class AnyRealmValueListTests: AnyRealmValueListTestsBase, @unchecked Sendable { private func assertEqual(_ obj: AnyRealmValue, _ anotherObj: AnyRealmValue) { if case let .object(a) = obj, case let .object(b) = anotherObj { XCTAssertEqual((a as! SwiftStringObject).stringCol, (b as! SwiftStringObject).stringCol) @@ -487,7 +487,7 @@ class AnyRealmValueListTests: AnyRealmValu } } -class MinMaxAnyRealmValueListTests: AnyRealmValueListTestsBase { +class MinMaxAnyRealmValueListTests: AnyRealmValueListTestsBase, @unchecked Sendable { func testMin() { XCTAssertNil(array.min()) array.append(objectsIn: values.reversed()) @@ -501,7 +501,7 @@ class MinMaxAnyRealmValueListTests: AnyRea } } -class AddableAnyRealmValueListTests: AnyRealmValueListTestsBase where V: NumericValueFactory { +class AddableAnyRealmValueListTests: AnyRealmValueListTestsBase, @unchecked Sendable where V: NumericValueFactory { func testSum() { if array.realm != nil { XCTAssertEqual(array.sum().intValue, nil) @@ -547,7 +547,7 @@ func addAnyRealmValueTests(_ suite: XCTestSuite, _ type: OF.T AddableAnyRealmValueListTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedAnyRealmValueListTests: TestCase { +class UnmanagedAnyRealmValueListTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged AnyRealmValue Lists") addAnyRealmValueTests(suite, UnmanagedObjectFactory.self) @@ -555,7 +555,7 @@ class UnmanagedAnyRealmValueListTests: TestCase { } } -class ManagedAnyRealmValueListTests: TestCase { +class ManagedAnyRealmValueListTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed AnyRealmValue Lists") addAnyRealmValueTests(suite, ManagedObjectFactory.self) @@ -565,7 +565,7 @@ class ManagedAnyRealmValueListTests: TestCase { // MARK: - Set tests -class AnyRealmValueSetTestsBase: TestCase { +class AnyRealmValueSetTestsBase: TestCase, @unchecked Sendable { var realm: Realm? var obj: ModernAllTypesObject! var obj2: ModernAllTypesObject! @@ -590,7 +590,7 @@ class AnyRealmValueSetTestsBase: TestCase } } -class AnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase { +class AnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase, @unchecked Sendable { private func assertEqual(_ obj: AnyRealmValue, _ anotherObj: AnyRealmValue) { if case let .object(a) = obj, case let .object(b) = anotherObj { @@ -799,7 +799,7 @@ class AnyRealmValueMutableSetTests: AnyRea } } -class MinMaxAnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase { +class MinMaxAnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase, @unchecked Sendable { func testMin() { XCTAssertNil(mutableSet.min()) mutableSet.insert(objectsIn: values) @@ -813,7 +813,7 @@ class MinMaxAnyRealmValueMutableSetTests: } } -class AddableAnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase where V: NumericValueFactory { +class AddableAnyRealmValueMutableSetTests: AnyRealmValueSetTestsBase, @unchecked Sendable where V: NumericValueFactory { func testSum() { if mutableSet.realm != nil { XCTAssertEqual(mutableSet.sum().intValue, nil) @@ -858,7 +858,7 @@ func addAnyRealmValueMutableSetTests(_ suite: XCTestSuite, _ AddableAnyRealmValueMutableSetTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedAnyRealmValueMutableSetTests: TestCase { +class UnmanagedAnyRealmValueMutableSetTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged Primitive Sets") addAnyRealmValueMutableSetTests(suite, UnmanagedObjectFactory.self) @@ -866,7 +866,7 @@ class UnmanagedAnyRealmValueMutableSetTests: TestCase { } } -class ManagedAnyRealmValueMutableSetTests: TestCase { +class ManagedAnyRealmValueMutableSetTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed Primitive Sets") addAnyRealmValueMutableSetTests(suite, ManagedObjectFactory.self) @@ -876,7 +876,7 @@ class ManagedAnyRealmValueMutableSetTests: TestCase { // MARK: - Map tests -class AnyRealmValueMapTestsBase: TestCase { +class AnyRealmValueMapTestsBase: TestCase, @unchecked Sendable { var realm: Realm? var obj: ModernAllTypesObject! var map: Map! @@ -897,7 +897,7 @@ class AnyRealmValueMapTestsBase: TestCase } } -class AnyRealmValueMapTests: AnyRealmValueMapTestsBase { +class AnyRealmValueMapTests: AnyRealmValueMapTestsBase, @unchecked Sendable { func testInvalidated() { XCTAssertFalse(map.isInvalidated) if let realm = obj.realm { @@ -1042,7 +1042,7 @@ class AnyRealmValueMapTests: AnyRealmValue } } -class MinMaxAnyRealmValueMapTests: AnyRealmValueMapTestsBase { +class MinMaxAnyRealmValueMapTests: AnyRealmValueMapTestsBase, @unchecked Sendable { func testMin() { XCTAssertNil(map.min()) map.merge(values) { $1 } @@ -1056,7 +1056,7 @@ class MinMaxAnyRealmValueMapTests: AnyReal } } -class AddableAnyRealmValueMapTests: AnyRealmValueMapTestsBase where V: NumericValueFactory { +class AddableAnyRealmValueMapTests: AnyRealmValueMapTestsBase, @unchecked Sendable where V: NumericValueFactory { func testSum() { XCTAssertEqual(map.sum().intValue, 0) map.merge(values) { $1 } @@ -1096,7 +1096,7 @@ func addAnyRealmValueMapTests(_ suite: XCTestSuite, _ type: O AddableAnyRealmValueMapTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedAnyRealmValueMapTests: TestCase { +class UnmanagedAnyRealmValueMapTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged AnyRealmValue Maps") addAnyRealmValueMapTests(suite, UnmanagedObjectFactory.self) @@ -1104,7 +1104,7 @@ class UnmanagedAnyRealmValueMapTests: TestCase { } } -class ManagedAnyRealmValueMapTests: TestCase { +class ManagedAnyRealmValueMapTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed AnyRealmValue Maps") addAnyRealmValueMapTests(suite, ManagedObjectFactory.self) diff --git a/RealmSwift/Tests/CodableTests.swift b/RealmSwift/Tests/CodableTests.swift index 9a8bf17963..48193bed3e 100644 --- a/RealmSwift/Tests/CodableTests.swift +++ b/RealmSwift/Tests/CodableTests.swift @@ -291,7 +291,7 @@ final class CodableEmbeddedObject: EmbeddedObject, Codable { } @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class CodableTests: TestCase { +class CodableTests: TestCase, @unchecked Sendable { let decoder = JSONDecoder() let encoder = JSONEncoder() @@ -775,321 +775,639 @@ class CodableTests: TestCase { // Note: "ZGVm" is Data("def".utf8).base64EncodedString() // This string needs to exactly match what JSONEncoder produces so that // we can validate round-tripping - let str = """ - { - "bool" : true, - "boolList" : [ - true - ], - "boolMap" : { - "foo" : true - }, - "boolOpt" : true, - "boolOptList" : [ - true - ], - "boolOptMap" : { - "foo" : true - }, - "boolOptSet" : [ - true - ], - "boolSet" : [ - true - ], - "data" : "ZGVm", - "dataList" : [ - "ZGVm" - ], - "dataMap" : { - "foo" : "ZGVm" - }, - "dataOpt" : "ZGVm", - "dataOptList" : [ - "ZGVm" - ], - "dataOptMap" : { - "foo" : "ZGVm" - }, - "dataOptSet" : [ - "ZGVm" - ], - "dataSet" : [ - "ZGVm" - ], - "date" : 2.5, - "dateList" : [ - 2.5 - ], - "dateMap" : { - "foo" : 2.5 - }, - "dateOpt" : 2.5, - "dateOptList" : [ - 2.5 - ], - "dateOptMap" : { - "foo" : 2.5 - }, - "dateOptSet" : [ - 2.5 - ], - "dateSet" : [ - 2.5 - ], - "decimal" : "1.5E2", - "decimalList" : [ - "1.5E2" - ], - "decimalMap" : { - "foo" : "1.5E2" - }, - "decimalOpt" : "1.5E2", - "decimalOptList" : [ - "1.5E2" - ], - "decimalOptMap" : { - "foo" : "1.5E2" - }, - "decimalOptSet" : [ - "1.5E2" - ], - "decimalSet" : [ - "1.5E2" - ], - "double" : 2.5, - "doubleList" : [ - 2.5 - ], - "doubleMap" : { - "foo" : 2.5 - }, - "doubleOpt" : 2.5, - "doubleOptList" : [ - 2.5 - ], - "doubleOptMap" : { - "foo" : 2.5 - }, - "doubleOptSet" : [ - 2.5 - ], - "doubleSet" : [ - 2.5 - ], - "embeddedObjectList" : [ - { - "value" : 8 - } - ], - "embeddedObjectOpt" : { - "value" : 6 - }, - "embeddedObjectOptMap" : { - "b" : { - "value" : 10 - } - }, - "float" : 2.5, - "floatList" : [ - 2.5 - ], - "floatMap" : { - "foo" : 2.5 - }, - "floatOpt" : 2.5, - "floatOptList" : [ - 2.5 - ], - "floatOptMap" : { - "foo" : 2.5 - }, - "floatOptSet" : [ - 2.5 - ], - "floatSet" : [ - 2.5 - ], - "int" : 123, - "int8" : 123, - "int8List" : [ - 123 - ], - "int8Map" : { - "foo" : 123 - }, - "int8Opt" : 123, - "int8OptList" : [ - 123 - ], - "int8OptMap" : { - "foo" : 123 - }, - "int8OptSet" : [ - 123 - ], - "int8Set" : [ - 123 - ], - "int16" : 123, - "int16List" : [ - 123 - ], - "int16Map" : { - "foo" : 123 - }, - "int16Opt" : 123, - "int16OptList" : [ - 123 - ], - "int16OptMap" : { - "foo" : 123 - }, - "int16OptSet" : [ - 123 - ], - "int16Set" : [ - 123 - ], - "int32" : 123, - "int32List" : [ - 123 - ], - "int32Map" : { - "foo" : 123 - }, - "int32Opt" : 123, - "int32OptList" : [ - 123 - ], - "int32OptMap" : { - "foo" : 123 - }, - "int32OptSet" : [ - 123 - ], - "int32Set" : [ - 123 - ], - "int64" : 123, - "int64List" : [ - 123 - ], - "int64Map" : { - "foo" : 123 - }, - "int64Opt" : 123, - "int64OptList" : [ - 123 - ], - "int64OptMap" : { - "foo" : 123 - }, - "int64OptSet" : [ - 123 - ], - "int64Set" : [ - 123 - ], - "intList" : [ - 123 - ], - "intMap" : { - "foo" : 123 - }, - "intOpt" : 123, - "intOptList" : [ - 123 - ], - "intOptMap" : { - "foo" : 123 - }, - "intOptSet" : [ - 123 - ], - "intSet" : [ - 123 - ], - "objectId" : "1234567890abcdef12345678", - "objectIdList" : [ - "1234567890abcdef12345678" - ], - "objectIdMap" : { - "foo" : "1234567890abcdef12345678" - }, - "objectIdOpt" : "1234567890abcdef12345678", - "objectIdOptList" : [ - "1234567890abcdef12345678" - ], - "objectIdOptMap" : { - "foo" : "1234567890abcdef12345678" - }, - "objectIdOptSet" : [ - "1234567890abcdef12345678" - ], - "objectIdSet" : [ - "1234567890abcdef12345678" - ], - "objectList" : [ + let str = if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *) { + """ { - "value" : 7 + "bool" : true, + "boolList" : [ + true + ], + "boolMap" : { + "foo" : true + }, + "boolOpt" : true, + "boolOptList" : [ + true + ], + "boolOptMap" : { + "foo" : true + }, + "boolOptSet" : [ + true + ], + "boolSet" : [ + true + ], + "data" : "ZGVm", + "dataList" : [ + "ZGVm" + ], + "dataMap" : { + "foo" : "ZGVm" + }, + "dataOpt" : "ZGVm", + "dataOptList" : [ + "ZGVm" + ], + "dataOptMap" : { + "foo" : "ZGVm" + }, + "dataOptSet" : [ + "ZGVm" + ], + "dataSet" : [ + "ZGVm" + ], + "date" : 2.5, + "dateList" : [ + 2.5 + ], + "dateMap" : { + "foo" : 2.5 + }, + "dateOpt" : 2.5, + "dateOptList" : [ + 2.5 + ], + "dateOptMap" : { + "foo" : 2.5 + }, + "dateOptSet" : [ + 2.5 + ], + "dateSet" : [ + 2.5 + ], + "decimal" : "1.5E2", + "decimalList" : [ + "1.5E2" + ], + "decimalMap" : { + "foo" : "1.5E2" + }, + "decimalOpt" : "1.5E2", + "decimalOptList" : [ + "1.5E2" + ], + "decimalOptMap" : { + "foo" : "1.5E2" + }, + "decimalOptSet" : [ + "1.5E2" + ], + "decimalSet" : [ + "1.5E2" + ], + "double" : 2.5, + "doubleList" : [ + 2.5 + ], + "doubleMap" : { + "foo" : 2.5 + }, + "doubleOpt" : 2.5, + "doubleOptList" : [ + 2.5 + ], + "doubleOptMap" : { + "foo" : 2.5 + }, + "doubleOptSet" : [ + 2.5 + ], + "doubleSet" : [ + 2.5 + ], + "embeddedObjectList" : [ + { + "value" : 8 + } + ], + "embeddedObjectOpt" : { + "value" : 6 + }, + "embeddedObjectOptMap" : { + "b" : { + "value" : 10 + } + }, + "float" : 2.5, + "floatList" : [ + 2.5 + ], + "floatMap" : { + "foo" : 2.5 + }, + "floatOpt" : 2.5, + "floatOptList" : [ + 2.5 + ], + "floatOptMap" : { + "foo" : 2.5 + }, + "floatOptSet" : [ + 2.5 + ], + "floatSet" : [ + 2.5 + ], + "int" : 123, + "int16" : 123, + "int16List" : [ + 123 + ], + "int16Map" : { + "foo" : 123 + }, + "int16Opt" : 123, + "int16OptList" : [ + 123 + ], + "int16OptMap" : { + "foo" : 123 + }, + "int16OptSet" : [ + 123 + ], + "int16Set" : [ + 123 + ], + "int32" : 123, + "int32List" : [ + 123 + ], + "int32Map" : { + "foo" : 123 + }, + "int32Opt" : 123, + "int32OptList" : [ + 123 + ], + "int32OptMap" : { + "foo" : 123 + }, + "int32OptSet" : [ + 123 + ], + "int32Set" : [ + 123 + ], + "int64" : 123, + "int64List" : [ + 123 + ], + "int64Map" : { + "foo" : 123 + }, + "int64Opt" : 123, + "int64OptList" : [ + 123 + ], + "int64OptMap" : { + "foo" : 123 + }, + "int64OptSet" : [ + 123 + ], + "int64Set" : [ + 123 + ], + "int8" : 123, + "int8List" : [ + 123 + ], + "int8Map" : { + "foo" : 123 + }, + "int8Opt" : 123, + "int8OptList" : [ + 123 + ], + "int8OptMap" : { + "foo" : 123 + }, + "int8OptSet" : [ + 123 + ], + "int8Set" : [ + 123 + ], + "intList" : [ + 123 + ], + "intMap" : { + "foo" : 123 + }, + "intOpt" : 123, + "intOptList" : [ + 123 + ], + "intOptMap" : { + "foo" : 123 + }, + "intOptSet" : [ + 123 + ], + "intSet" : [ + 123 + ], + "objectId" : "1234567890abcdef12345678", + "objectIdList" : [ + "1234567890abcdef12345678" + ], + "objectIdMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOpt" : "1234567890abcdef12345678", + "objectIdOptList" : [ + "1234567890abcdef12345678" + ], + "objectIdOptMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOptSet" : [ + "1234567890abcdef12345678" + ], + "objectIdSet" : [ + "1234567890abcdef12345678" + ], + "objectList" : [ + { + "value" : 7 + } + ], + "objectOpt" : { + "value" : 5 + }, + "objectOptMap" : { + "a" : { + "value" : 9 + } + }, + "objectSet" : [ + { + "value" : 9 + } + ], + "string" : "abc", + "stringList" : [ + "abc" + ], + "stringMap" : { + "foo" : "abc" + }, + "stringOpt" : "abc", + "stringOptList" : [ + "abc" + ], + "stringOptMap" : { + "foo" : "abc" + }, + "stringOptSet" : [ + "abc" + ], + "stringSet" : [ + "abc" + ], + "uuid" : "00000000-0000-0000-0000-000000000000", + "uuidList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOpt" : "00000000-0000-0000-0000-000000000000", + "uuidOptList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidOptMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOptSet" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidSet" : [ + "00000000-0000-0000-0000-000000000000" + ] } - ], - "objectOpt" : { - "value" : 5 - }, - "objectOptMap" : { - "a" : { - "value" : 9 - } - }, - "objectSet" : [ + """ + } else { + """ { - "value" : 9 + "bool" : true, + "boolList" : [ + true + ], + "boolMap" : { + "foo" : true + }, + "boolOpt" : true, + "boolOptList" : [ + true + ], + "boolOptMap" : { + "foo" : true + }, + "boolOptSet" : [ + true + ], + "boolSet" : [ + true + ], + "data" : "ZGVm", + "dataList" : [ + "ZGVm" + ], + "dataMap" : { + "foo" : "ZGVm" + }, + "dataOpt" : "ZGVm", + "dataOptList" : [ + "ZGVm" + ], + "dataOptMap" : { + "foo" : "ZGVm" + }, + "dataOptSet" : [ + "ZGVm" + ], + "dataSet" : [ + "ZGVm" + ], + "date" : 2.5, + "dateList" : [ + 2.5 + ], + "dateMap" : { + "foo" : 2.5 + }, + "dateOpt" : 2.5, + "dateOptList" : [ + 2.5 + ], + "dateOptMap" : { + "foo" : 2.5 + }, + "dateOptSet" : [ + 2.5 + ], + "dateSet" : [ + 2.5 + ], + "decimal" : "1.5E2", + "decimalList" : [ + "1.5E2" + ], + "decimalMap" : { + "foo" : "1.5E2" + }, + "decimalOpt" : "1.5E2", + "decimalOptList" : [ + "1.5E2" + ], + "decimalOptMap" : { + "foo" : "1.5E2" + }, + "decimalOptSet" : [ + "1.5E2" + ], + "decimalSet" : [ + "1.5E2" + ], + "double" : 2.5, + "doubleList" : [ + 2.5 + ], + "doubleMap" : { + "foo" : 2.5 + }, + "doubleOpt" : 2.5, + "doubleOptList" : [ + 2.5 + ], + "doubleOptMap" : { + "foo" : 2.5 + }, + "doubleOptSet" : [ + 2.5 + ], + "doubleSet" : [ + 2.5 + ], + "embeddedObjectList" : [ + { + "value" : 8 + } + ], + "embeddedObjectOpt" : { + "value" : 6 + }, + "embeddedObjectOptMap" : { + "b" : { + "value" : 10 + } + }, + "float" : 2.5, + "floatList" : [ + 2.5 + ], + "floatMap" : { + "foo" : 2.5 + }, + "floatOpt" : 2.5, + "floatOptList" : [ + 2.5 + ], + "floatOptMap" : { + "foo" : 2.5 + }, + "floatOptSet" : [ + 2.5 + ], + "floatSet" : [ + 2.5 + ], + "int" : 123, + "int8" : 123, + "int8List" : [ + 123 + ], + "int8Map" : { + "foo" : 123 + }, + "int8Opt" : 123, + "int8OptList" : [ + 123 + ], + "int8OptMap" : { + "foo" : 123 + }, + "int8OptSet" : [ + 123 + ], + "int8Set" : [ + 123 + ], + "int16" : 123, + "int16List" : [ + 123 + ], + "int16Map" : { + "foo" : 123 + }, + "int16Opt" : 123, + "int16OptList" : [ + 123 + ], + "int16OptMap" : { + "foo" : 123 + }, + "int16OptSet" : [ + 123 + ], + "int16Set" : [ + 123 + ], + "int32" : 123, + "int32List" : [ + 123 + ], + "int32Map" : { + "foo" : 123 + }, + "int32Opt" : 123, + "int32OptList" : [ + 123 + ], + "int32OptMap" : { + "foo" : 123 + }, + "int32OptSet" : [ + 123 + ], + "int32Set" : [ + 123 + ], + "int64" : 123, + "int64List" : [ + 123 + ], + "int64Map" : { + "foo" : 123 + }, + "int64Opt" : 123, + "int64OptList" : [ + 123 + ], + "int64OptMap" : { + "foo" : 123 + }, + "int64OptSet" : [ + 123 + ], + "int64Set" : [ + 123 + ], + "intList" : [ + 123 + ], + "intMap" : { + "foo" : 123 + }, + "intOpt" : 123, + "intOptList" : [ + 123 + ], + "intOptMap" : { + "foo" : 123 + }, + "intOptSet" : [ + 123 + ], + "intSet" : [ + 123 + ], + "objectId" : "1234567890abcdef12345678", + "objectIdList" : [ + "1234567890abcdef12345678" + ], + "objectIdMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOpt" : "1234567890abcdef12345678", + "objectIdOptList" : [ + "1234567890abcdef12345678" + ], + "objectIdOptMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOptSet" : [ + "1234567890abcdef12345678" + ], + "objectIdSet" : [ + "1234567890abcdef12345678" + ], + "objectList" : [ + { + "value" : 7 + } + ], + "objectOpt" : { + "value" : 5 + }, + "objectOptMap" : { + "a" : { + "value" : 9 + } + }, + "objectSet" : [ + { + "value" : 9 + } + ], + "string" : "abc", + "stringList" : [ + "abc" + ], + "stringMap" : { + "foo" : "abc" + }, + "stringOpt" : "abc", + "stringOptList" : [ + "abc" + ], + "stringOptMap" : { + "foo" : "abc" + }, + "stringOptSet" : [ + "abc" + ], + "stringSet" : [ + "abc" + ], + "uuid" : "00000000-0000-0000-0000-000000000000", + "uuidList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOpt" : "00000000-0000-0000-0000-000000000000", + "uuidOptList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidOptMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOptSet" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidSet" : [ + "00000000-0000-0000-0000-000000000000" + ] } - ], - "string" : "abc", - "stringList" : [ - "abc" - ], - "stringMap" : { - "foo" : "abc" - }, - "stringOpt" : "abc", - "stringOptList" : [ - "abc" - ], - "stringOptMap" : { - "foo" : "abc" - }, - "stringOptSet" : [ - "abc" - ], - "stringSet" : [ - "abc" - ], - "uuid" : "00000000-0000-0000-0000-000000000000", - "uuidList" : [ - "00000000-0000-0000-0000-000000000000" - ], - "uuidMap" : { - "foo" : "00000000-0000-0000-0000-000000000000" - }, - "uuidOpt" : "00000000-0000-0000-0000-000000000000", - "uuidOptList" : [ - "00000000-0000-0000-0000-000000000000" - ], - "uuidOptMap" : { - "foo" : "00000000-0000-0000-0000-000000000000" - }, - "uuidOptSet" : [ - "00000000-0000-0000-0000-000000000000" - ], - "uuidSet" : [ - "00000000-0000-0000-0000-000000000000" - ] + """ } - """ let decoder = JSONDecoder() let obj = try decoder.decode(ModernCodableObject.self, from: Data(str.utf8)) @@ -1218,7 +1536,7 @@ class CodableTests: TestCase { // that the original string be formatted how JSONEncoder formats things) encoder.outputFormatting = [.prettyPrinted, .sortedKeys] // swiftlint:disable:next non_optional_string_data_conversion - let actual = try String(data: encoder.encode(obj), encoding: .utf8) + let actual = try XCTUnwrap(String(data: encoder.encode(obj), encoding: .utf8)) XCTAssertEqual(str, actual) let realm = try! Realm() @@ -1233,307 +1551,611 @@ class CodableTests: TestCase { // Note: "ZGVm" is Data("def".utf8).base64EncodedString() // This string needs to exactly match what JSONEncoder produces so that // we can validate round-tripping - let str = """ - { - "bool" : true, - "boolList" : [ - true - ], - "boolMap" : { - "foo" : true - }, - "boolOpt" : null, - "boolOptList" : [ - null - ], - "boolOptMap" : { - "foo" : null - }, - "boolOptSet" : [ - null - ], - "boolSet" : [ - true - ], - "data" : "ZGVm", - "dataList" : [ - "ZGVm" - ], - "dataMap" : { - "foo" : "ZGVm" - }, - "dataOpt" : null, - "dataOptList" : [ - null - ], - "dataOptMap" : { - "foo" : null - }, - "dataOptSet" : [ - null - ], - "dataSet" : [ - "ZGVm" - ], - "date" : 2.5, - "dateList" : [ - 2.5 - ], - "dateMap" : { - "foo" : 2.5 - }, - "dateOpt" : null, - "dateOptList" : [ - null - ], - "dateOptMap" : { - "foo" : null - }, - "dateOptSet" : [ - null - ], - "dateSet" : [ - 2.5 - ], - "decimal" : "1.5E2", - "decimalList" : [ - "1.5E2" - ], - "decimalMap" : { - "foo" : "1.5E2" - }, - "decimalOpt" : null, - "decimalOptList" : [ - null - ], - "decimalOptMap" : { - "foo" : null - }, - "decimalOptSet" : [ - null - ], - "decimalSet" : [ - "1.5E2" - ], - "double" : 2.5, - "doubleList" : [ - 2.5 - ], - "doubleMap" : { - "foo" : 2.5 - }, - "doubleOpt" : null, - "doubleOptList" : [ - null - ], - "doubleOptMap" : { - "foo" : null - }, - "doubleOptSet" : [ - null - ], - "doubleSet" : [ - 2.5 - ], - "embeddedObjectList" : [ - - ], - "embeddedObjectOpt" : null, - "embeddedObjectOptMap" : { - "foo" : null - }, - "float" : 2.5, - "floatList" : [ - 2.5 - ], - "floatMap" : { - "foo" : 2.5 - }, - "floatOpt" : null, - "floatOptList" : [ - null - ], - "floatOptMap" : { - "foo" : null - }, - "floatOptSet" : [ - null - ], - "floatSet" : [ - 2.5 - ], - "int" : 123, - "int8" : 123, - "int8List" : [ - 123 - ], - "int8Map" : { - "foo" : 123 - }, - "int8Opt" : null, - "int8OptList" : [ - null - ], - "int8OptMap" : { - "foo" : null - }, - "int8OptSet" : [ - null - ], - "int8Set" : [ - 123 - ], - "int16" : 123, - "int16List" : [ - 123 - ], - "int16Map" : { - "foo" : 123 - }, - "int16Opt" : null, - "int16OptList" : [ - null - ], - "int16OptMap" : { - "foo" : null - }, - "int16OptSet" : [ - null - ], - "int16Set" : [ - 123 - ], - "int32" : 123, - "int32List" : [ - 123 - ], - "int32Map" : { - "foo" : 123 - }, - "int32Opt" : null, - "int32OptList" : [ - null - ], - "int32OptMap" : { - "foo" : null - }, - "int32OptSet" : [ - null - ], - "int32Set" : [ - 123 - ], - "int64" : 123, - "int64List" : [ - 123 - ], - "int64Map" : { - "foo" : 123 - }, - "int64Opt" : null, - "int64OptList" : [ - null - ], - "int64OptMap" : { - "foo" : null - }, - "int64OptSet" : [ - null - ], - "int64Set" : [ - 123 - ], - "intList" : [ - 123 - ], - "intMap" : { - "foo" : 123 - }, - "intOpt" : null, - "intOptList" : [ - null - ], - "intOptMap" : { - "foo" : null - }, - "intOptSet" : [ - null - ], - "intSet" : [ - 123 - ], - "objectId" : "1234567890abcdef12345678", - "objectIdList" : [ - "1234567890abcdef12345678" - ], - "objectIdMap" : { - "foo" : "1234567890abcdef12345678" - }, - "objectIdOpt" : null, - "objectIdOptList" : [ - null - ], - "objectIdOptMap" : { - "foo" : null - }, - "objectIdOptSet" : [ - null - ], - "objectIdSet" : [ - "1234567890abcdef12345678" - ], - "objectList" : [ - - ], - "objectOpt" : null, - "objectOptMap" : { - "foo" : null - }, - "objectSet" : [ - - ], - "string" : "abc", - "stringList" : [ - "abc" - ], - "stringMap" : { - "foo" : "abc" - }, - "stringOpt" : null, - "stringOptList" : [ - null - ], - "stringOptMap" : { - "foo" : null - }, - "stringOptSet" : [ - null - ], - "stringSet" : [ - "abc" - ], - "uuid" : "00000000-0000-0000-0000-000000000000", - "uuidList" : [ - "00000000-0000-0000-0000-000000000000" - ], - "uuidMap" : { - "foo" : "00000000-0000-0000-0000-000000000000" - }, - "uuidOpt" : null, - "uuidOptList" : [ - null - ], - "uuidOptMap" : { - "foo" : null - }, - "uuidOptSet" : [ - null - ], - "uuidSet" : [ - "00000000-0000-0000-0000-000000000000" - ] + let str = if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *) { + """ + { + "bool" : true, + "boolList" : [ + true + ], + "boolMap" : { + "foo" : true + }, + "boolOpt" : null, + "boolOptList" : [ + null + ], + "boolOptMap" : { + "foo" : null + }, + "boolOptSet" : [ + null + ], + "boolSet" : [ + true + ], + "data" : "ZGVm", + "dataList" : [ + "ZGVm" + ], + "dataMap" : { + "foo" : "ZGVm" + }, + "dataOpt" : null, + "dataOptList" : [ + null + ], + "dataOptMap" : { + "foo" : null + }, + "dataOptSet" : [ + null + ], + "dataSet" : [ + "ZGVm" + ], + "date" : 2.5, + "dateList" : [ + 2.5 + ], + "dateMap" : { + "foo" : 2.5 + }, + "dateOpt" : null, + "dateOptList" : [ + null + ], + "dateOptMap" : { + "foo" : null + }, + "dateOptSet" : [ + null + ], + "dateSet" : [ + 2.5 + ], + "decimal" : "1.5E2", + "decimalList" : [ + "1.5E2" + ], + "decimalMap" : { + "foo" : "1.5E2" + }, + "decimalOpt" : null, + "decimalOptList" : [ + null + ], + "decimalOptMap" : { + "foo" : null + }, + "decimalOptSet" : [ + null + ], + "decimalSet" : [ + "1.5E2" + ], + "double" : 2.5, + "doubleList" : [ + 2.5 + ], + "doubleMap" : { + "foo" : 2.5 + }, + "doubleOpt" : null, + "doubleOptList" : [ + null + ], + "doubleOptMap" : { + "foo" : null + }, + "doubleOptSet" : [ + null + ], + "doubleSet" : [ + 2.5 + ], + "embeddedObjectList" : [ + + ], + "embeddedObjectOpt" : null, + "embeddedObjectOptMap" : { + "foo" : null + }, + "float" : 2.5, + "floatList" : [ + 2.5 + ], + "floatMap" : { + "foo" : 2.5 + }, + "floatOpt" : null, + "floatOptList" : [ + null + ], + "floatOptMap" : { + "foo" : null + }, + "floatOptSet" : [ + null + ], + "floatSet" : [ + 2.5 + ], + "int" : 123, + "int16" : 123, + "int16List" : [ + 123 + ], + "int16Map" : { + "foo" : 123 + }, + "int16Opt" : null, + "int16OptList" : [ + null + ], + "int16OptMap" : { + "foo" : null + }, + "int16OptSet" : [ + null + ], + "int16Set" : [ + 123 + ], + "int32" : 123, + "int32List" : [ + 123 + ], + "int32Map" : { + "foo" : 123 + }, + "int32Opt" : null, + "int32OptList" : [ + null + ], + "int32OptMap" : { + "foo" : null + }, + "int32OptSet" : [ + null + ], + "int32Set" : [ + 123 + ], + "int64" : 123, + "int64List" : [ + 123 + ], + "int64Map" : { + "foo" : 123 + }, + "int64Opt" : null, + "int64OptList" : [ + null + ], + "int64OptMap" : { + "foo" : null + }, + "int64OptSet" : [ + null + ], + "int64Set" : [ + 123 + ], + "int8" : 123, + "int8List" : [ + 123 + ], + "int8Map" : { + "foo" : 123 + }, + "int8Opt" : null, + "int8OptList" : [ + null + ], + "int8OptMap" : { + "foo" : null + }, + "int8OptSet" : [ + null + ], + "int8Set" : [ + 123 + ], + "intList" : [ + 123 + ], + "intMap" : { + "foo" : 123 + }, + "intOpt" : null, + "intOptList" : [ + null + ], + "intOptMap" : { + "foo" : null + }, + "intOptSet" : [ + null + ], + "intSet" : [ + 123 + ], + "objectId" : "1234567890abcdef12345678", + "objectIdList" : [ + "1234567890abcdef12345678" + ], + "objectIdMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOpt" : null, + "objectIdOptList" : [ + null + ], + "objectIdOptMap" : { + "foo" : null + }, + "objectIdOptSet" : [ + null + ], + "objectIdSet" : [ + "1234567890abcdef12345678" + ], + "objectList" : [ + + ], + "objectOpt" : null, + "objectOptMap" : { + "foo" : null + }, + "objectSet" : [ + + ], + "string" : "abc", + "stringList" : [ + "abc" + ], + "stringMap" : { + "foo" : "abc" + }, + "stringOpt" : null, + "stringOptList" : [ + null + ], + "stringOptMap" : { + "foo" : null + }, + "stringOptSet" : [ + null + ], + "stringSet" : [ + "abc" + ], + "uuid" : "00000000-0000-0000-0000-000000000000", + "uuidList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOpt" : null, + "uuidOptList" : [ + null + ], + "uuidOptMap" : { + "foo" : null + }, + "uuidOptSet" : [ + null + ], + "uuidSet" : [ + "00000000-0000-0000-0000-000000000000" + ] + } + """ + } else { + """ + { + "bool" : true, + "boolList" : [ + true + ], + "boolMap" : { + "foo" : true + }, + "boolOpt" : null, + "boolOptList" : [ + null + ], + "boolOptMap" : { + "foo" : null + }, + "boolOptSet" : [ + null + ], + "boolSet" : [ + true + ], + "data" : "ZGVm", + "dataList" : [ + "ZGVm" + ], + "dataMap" : { + "foo" : "ZGVm" + }, + "dataOpt" : null, + "dataOptList" : [ + null + ], + "dataOptMap" : { + "foo" : null + }, + "dataOptSet" : [ + null + ], + "dataSet" : [ + "ZGVm" + ], + "date" : 2.5, + "dateList" : [ + 2.5 + ], + "dateMap" : { + "foo" : 2.5 + }, + "dateOpt" : null, + "dateOptList" : [ + null + ], + "dateOptMap" : { + "foo" : null + }, + "dateOptSet" : [ + null + ], + "dateSet" : [ + 2.5 + ], + "decimal" : "1.5E2", + "decimalList" : [ + "1.5E2" + ], + "decimalMap" : { + "foo" : "1.5E2" + }, + "decimalOpt" : null, + "decimalOptList" : [ + null + ], + "decimalOptMap" : { + "foo" : null + }, + "decimalOptSet" : [ + null + ], + "decimalSet" : [ + "1.5E2" + ], + "double" : 2.5, + "doubleList" : [ + 2.5 + ], + "doubleMap" : { + "foo" : 2.5 + }, + "doubleOpt" : null, + "doubleOptList" : [ + null + ], + "doubleOptMap" : { + "foo" : null + }, + "doubleOptSet" : [ + null + ], + "doubleSet" : [ + 2.5 + ], + "embeddedObjectList" : [ + + ], + "embeddedObjectOpt" : null, + "embeddedObjectOptMap" : { + "foo" : null + }, + "float" : 2.5, + "floatList" : [ + 2.5 + ], + "floatMap" : { + "foo" : 2.5 + }, + "floatOpt" : null, + "floatOptList" : [ + null + ], + "floatOptMap" : { + "foo" : null + }, + "floatOptSet" : [ + null + ], + "floatSet" : [ + 2.5 + ], + "int" : 123, + "int8" : 123, + "int8List" : [ + 123 + ], + "int8Map" : { + "foo" : 123 + }, + "int8Opt" : null, + "int8OptList" : [ + null + ], + "int8OptMap" : { + "foo" : null + }, + "int8OptSet" : [ + null + ], + "int8Set" : [ + 123 + ], + "int16" : 123, + "int16List" : [ + 123 + ], + "int16Map" : { + "foo" : 123 + }, + "int16Opt" : null, + "int16OptList" : [ + null + ], + "int16OptMap" : { + "foo" : null + }, + "int16OptSet" : [ + null + ], + "int16Set" : [ + 123 + ], + "int32" : 123, + "int32List" : [ + 123 + ], + "int32Map" : { + "foo" : 123 + }, + "int32Opt" : null, + "int32OptList" : [ + null + ], + "int32OptMap" : { + "foo" : null + }, + "int32OptSet" : [ + null + ], + "int32Set" : [ + 123 + ], + "int64" : 123, + "int64List" : [ + 123 + ], + "int64Map" : { + "foo" : 123 + }, + "int64Opt" : null, + "int64OptList" : [ + null + ], + "int64OptMap" : { + "foo" : null + }, + "int64OptSet" : [ + null + ], + "int64Set" : [ + 123 + ], + "intList" : [ + 123 + ], + "intMap" : { + "foo" : 123 + }, + "intOpt" : null, + "intOptList" : [ + null + ], + "intOptMap" : { + "foo" : null + }, + "intOptSet" : [ + null + ], + "intSet" : [ + 123 + ], + "objectId" : "1234567890abcdef12345678", + "objectIdList" : [ + "1234567890abcdef12345678" + ], + "objectIdMap" : { + "foo" : "1234567890abcdef12345678" + }, + "objectIdOpt" : null, + "objectIdOptList" : [ + null + ], + "objectIdOptMap" : { + "foo" : null + }, + "objectIdOptSet" : [ + null + ], + "objectIdSet" : [ + "1234567890abcdef12345678" + ], + "objectList" : [ + + ], + "objectOpt" : null, + "objectOptMap" : { + "foo" : null + }, + "objectSet" : [ + + ], + "string" : "abc", + "stringList" : [ + "abc" + ], + "stringMap" : { + "foo" : "abc" + }, + "stringOpt" : null, + "stringOptList" : [ + null + ], + "stringOptMap" : { + "foo" : null + }, + "stringOptSet" : [ + null + ], + "stringSet" : [ + "abc" + ], + "uuid" : "00000000-0000-0000-0000-000000000000", + "uuidList" : [ + "00000000-0000-0000-0000-000000000000" + ], + "uuidMap" : { + "foo" : "00000000-0000-0000-0000-000000000000" + }, + "uuidOpt" : null, + "uuidOptList" : [ + null + ], + "uuidOptMap" : { + "foo" : null + }, + "uuidOptSet" : [ + null + ], + "uuidSet" : [ + "00000000-0000-0000-0000-000000000000" + ] + } + """ } - """ let decoder = JSONDecoder() let obj = try decoder.decode(ModernCodableObject.self, from: Data(str.utf8)) @@ -1780,10 +2402,6 @@ class CodableTests: TestCase { try "length: \(data.count)".encode(to: encoder) } - func data(_ length: Int) -> Data { - Data(repeating: 0, count: length) - } - let obj = ModernCodableObject() obj.data = Data(repeating: 0, count: 1) obj.dataOpt = Data(repeating: 0, count: 2) @@ -1814,8 +2432,13 @@ class CodableTests: TestCase { obj.uuid = UUID(uuidString: "00000000-0000-0000-0000-000000000000")! obj.date = Date(timeIntervalSince1970: 0) // swiftlint:disable:next non_optional_string_data_conversion - let actual = try String(data: encoder.encode(obj), encoding: .utf8) - let expected = #"{"bool":false,"bool_list":[],"bool_map":{},"bool_opt":null,"bool_opt_list":[],"bool_opt_map":{},"bool_opt_set":[],"bool_set":[],"data":"","data_list":[],"data_map":{},"data_opt":null,"data_opt_list":[],"data_opt_map":{},"data_opt_set":[],"data_set":[],"date":-978307200,"date_list":[],"date_map":{},"date_opt":null,"date_opt_list":[],"date_opt_map":{},"date_opt_set":[],"date_set":[],"decimal":"0","decimal_list":[],"decimal_map":{},"decimal_opt":null,"decimal_opt_list":[],"decimal_opt_map":{},"decimal_opt_set":[],"decimal_set":[],"double":0,"double_list":[],"double_map":{},"double_opt":null,"double_opt_list":[],"double_opt_map":{},"double_opt_set":[],"double_set":[],"embedded_object_list":[],"embedded_object_opt":null,"embedded_object_opt_map":{},"float":0,"float_list":[],"float_map":{},"float_opt":null,"float_opt_list":[],"float_opt_map":{},"float_opt_set":[],"float_set":[],"int":0,"int_list":[],"int_map":{},"int_opt":null,"int_opt_list":[],"int_opt_map":{},"int_opt_set":[],"int_set":[],"int8":0,"int8_list":[],"int8_map":{},"int8_opt":null,"int8_opt_list":[],"int8_opt_map":{},"int8_opt_set":[],"int8_set":[],"int16":0,"int16_list":[],"int16_map":{},"int16_opt":null,"int16_opt_list":[],"int16_opt_map":{},"int16_opt_set":[],"int16_set":[],"int32":0,"int32_list":[],"int32_map":{},"int32_opt":null,"int32_opt_list":[],"int32_opt_map":{},"int32_opt_set":[],"int32_set":[],"int64":0,"int64_list":[],"int64_map":{},"int64_opt":null,"int64_opt_list":[],"int64_opt_map":{},"int64_opt_set":[],"int64_set":[],"object_id":"1234567890abcdef12345678","object_id_list":[],"object_id_map":{},"object_id_opt":null,"object_id_opt_list":[],"object_id_opt_map":{},"object_id_opt_set":[],"object_id_set":[],"object_list":[],"object_opt":null,"object_opt_map":{},"object_set":[],"string":"","string_list":[],"string_map":{},"string_opt":null,"string_opt_list":[],"string_opt_map":{},"string_opt_set":[],"string_set":[],"uuid":"00000000-0000-0000-0000-000000000000","uuid_list":[],"uuid_map":{},"uuid_opt":null,"uuid_opt_list":[],"uuid_opt_map":{},"uuid_opt_set":[],"uuid_set":[]}"# + let actual = try XCTUnwrap(String(data: encoder.encode(obj), encoding: .utf8)) + // Before the 2024 OS versions, int8 was sorted before int16 + let expected = if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *) { + #"{"bool":false,"bool_list":[],"bool_map":{},"bool_opt":null,"bool_opt_list":[],"bool_opt_map":{},"bool_opt_set":[],"bool_set":[],"data":"","data_list":[],"data_map":{},"data_opt":null,"data_opt_list":[],"data_opt_map":{},"data_opt_set":[],"data_set":[],"date":-978307200,"date_list":[],"date_map":{},"date_opt":null,"date_opt_list":[],"date_opt_map":{},"date_opt_set":[],"date_set":[],"decimal":"0","decimal_list":[],"decimal_map":{},"decimal_opt":null,"decimal_opt_list":[],"decimal_opt_map":{},"decimal_opt_set":[],"decimal_set":[],"double":0,"double_list":[],"double_map":{},"double_opt":null,"double_opt_list":[],"double_opt_map":{},"double_opt_set":[],"double_set":[],"embedded_object_list":[],"embedded_object_opt":null,"embedded_object_opt_map":{},"float":0,"float_list":[],"float_map":{},"float_opt":null,"float_opt_list":[],"float_opt_map":{},"float_opt_set":[],"float_set":[],"int":0,"int16":0,"int16_list":[],"int16_map":{},"int16_opt":null,"int16_opt_list":[],"int16_opt_map":{},"int16_opt_set":[],"int16_set":[],"int32":0,"int32_list":[],"int32_map":{},"int32_opt":null,"int32_opt_list":[],"int32_opt_map":{},"int32_opt_set":[],"int32_set":[],"int64":0,"int64_list":[],"int64_map":{},"int64_opt":null,"int64_opt_list":[],"int64_opt_map":{},"int64_opt_set":[],"int64_set":[],"int8":0,"int8_list":[],"int8_map":{},"int8_opt":null,"int8_opt_list":[],"int8_opt_map":{},"int8_opt_set":[],"int8_set":[],"int_list":[],"int_map":{},"int_opt":null,"int_opt_list":[],"int_opt_map":{},"int_opt_set":[],"int_set":[],"object_id":"1234567890abcdef12345678","object_id_list":[],"object_id_map":{},"object_id_opt":null,"object_id_opt_list":[],"object_id_opt_map":{},"object_id_opt_set":[],"object_id_set":[],"object_list":[],"object_opt":null,"object_opt_map":{},"object_set":[],"string":"","string_list":[],"string_map":{},"string_opt":null,"string_opt_list":[],"string_opt_map":{},"string_opt_set":[],"string_set":[],"uuid":"00000000-0000-0000-0000-000000000000","uuid_list":[],"uuid_map":{},"uuid_opt":null,"uuid_opt_list":[],"uuid_opt_map":{},"uuid_opt_set":[],"uuid_set":[]}"# + } else { + #"{"bool":false,"bool_list":[],"bool_map":{},"bool_opt":null,"bool_opt_list":[],"bool_opt_map":{},"bool_opt_set":[],"bool_set":[],"data":"","data_list":[],"data_map":{},"data_opt":null,"data_opt_list":[],"data_opt_map":{},"data_opt_set":[],"data_set":[],"date":-978307200,"date_list":[],"date_map":{},"date_opt":null,"date_opt_list":[],"date_opt_map":{},"date_opt_set":[],"date_set":[],"decimal":"0","decimal_list":[],"decimal_map":{},"decimal_opt":null,"decimal_opt_list":[],"decimal_opt_map":{},"decimal_opt_set":[],"decimal_set":[],"double":0,"double_list":[],"double_map":{},"double_opt":null,"double_opt_list":[],"double_opt_map":{},"double_opt_set":[],"double_set":[],"embedded_object_list":[],"embedded_object_opt":null,"embedded_object_opt_map":{},"float":0,"float_list":[],"float_map":{},"float_opt":null,"float_opt_list":[],"float_opt_map":{},"float_opt_set":[],"float_set":[],"int":0,"int_list":[],"int_map":{},"int_opt":null,"int_opt_list":[],"int_opt_map":{},"int_opt_set":[],"int_set":[],"int8":0,"int8_list":[],"int8_map":{},"int8_opt":null,"int8_opt_list":[],"int8_opt_map":{},"int8_opt_set":[],"int8_set":[],"int16":0,"int16_list":[],"int16_map":{},"int16_opt":null,"int16_opt_list":[],"int16_opt_map":{},"int16_opt_set":[],"int16_set":[],"int32":0,"int32_list":[],"int32_map":{},"int32_opt":null,"int32_opt_list":[],"int32_opt_map":{},"int32_opt_set":[],"int32_set":[],"int64":0,"int64_list":[],"int64_map":{},"int64_opt":null,"int64_opt_list":[],"int64_opt_map":{},"int64_opt_set":[],"int64_set":[],"object_id":"1234567890abcdef12345678","object_id_list":[],"object_id_map":{},"object_id_opt":null,"object_id_opt_list":[],"object_id_opt_map":{},"object_id_opt_set":[],"object_id_set":[],"object_list":[],"object_opt":null,"object_opt_map":{},"object_set":[],"string":"","string_list":[],"string_map":{},"string_opt":null,"string_opt_list":[],"string_opt_map":{},"string_opt_set":[],"string_set":[],"uuid":"00000000-0000-0000-0000-000000000000","uuid_list":[],"uuid_map":{},"uuid_opt":null,"uuid_opt_list":[],"uuid_opt_map":{},"uuid_opt_set":[],"uuid_set":[]}"# + } XCTAssertEqual(expected, actual) } } diff --git a/RealmSwift/Tests/CombineTests.swift b/RealmSwift/Tests/CombineTests.swift index 921e454968..fbd85cfb77 100644 --- a/RealmSwift/Tests/CombineTests.swift +++ b/RealmSwift/Tests/CombineTests.swift @@ -48,7 +48,7 @@ func hasCombine() -> Bool { } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) -class ObjectIdentifiableTests: TestCase { +class ObjectIdentifiableTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { if hasCombine() { return super.defaultTestSuite @@ -94,7 +94,7 @@ class ObjectIdentifiableTests: TestCase { } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class CombinePublisherTestCase: TestCase { +class CombinePublisherTestCase: TestCase, @unchecked Sendable { var realm: Realm! var cancellable: AnyCancellable? var notificationToken: NotificationToken? @@ -144,7 +144,7 @@ class CombinePublisherTestCase: TestCase { } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class CombineRealmTests: CombinePublisherTestCase { +class CombineRealmTests: CombinePublisherTestCase, @unchecked Sendable { func testWillChangeLocalWrite() { var called = false cancellable = realm @@ -212,7 +212,7 @@ class CombineRealmTests: CombinePublisherTestCase { // MARK: - Object @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class CombineObjectPublisherTests: CombinePublisherTestCase { +class CombineObjectPublisherTests: CombinePublisherTestCase, @unchecked Sendable { var obj: SwiftIntObject! override func setUp() { @@ -786,7 +786,7 @@ private protocol CombineTestCollection { // MARK: - List, MutableSet @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -private class CombineCollectionPublisherTests: CombinePublisherTestCase +private class CombineCollectionPublisherTests: CombinePublisherTestCase, @unchecked Sendable where Collection: CombineTestCollection, Collection: RealmSubscribable { var collection: Collection! @@ -1414,7 +1414,7 @@ extension Results: CombineTestCollection where Element == ModernAllTypesObject { } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class ResultsPublisherTests: TestCase { +class ResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineCollectionPublisherTests>.testSuite("Results") } @@ -1444,7 +1444,7 @@ extension List: CombineTestCollection where Element == ModernAllTypesObject { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class ManagedListPublisherTests: TestCase { +class ManagedListPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineCollectionPublisherTests>.testSuite("List") } @@ -1473,7 +1473,7 @@ extension MutableSet: CombineTestCollection where Element == ModernAllTypesObjec } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class ManagedMutableSetPublisherTests: TestCase { +class ManagedMutableSetPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineCollectionPublisherTests>.testSuite("MutableSet") } @@ -1505,7 +1505,7 @@ extension LinkingObjects: CombineTestCollection where Element == ModernAllTypesO } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class LinkingObjectsPublisherTests: TestCase { +class LinkingObjectsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineCollectionPublisherTests>.testSuite("LinkingObjects") } @@ -1534,7 +1534,7 @@ extension AnyRealmCollection: CombineTestCollection where Element == ModernAllTy } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class AnyRealmCollectionPublisherTests: TestCase { +class AnyRealmCollectionPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineCollectionPublisherTests>.testSuite("AnyRealmCollection") } @@ -1543,7 +1543,7 @@ class AnyRealmCollectionPublisherTests: TestCase { // MARK: - Map @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -private class CombineMapPublisherTests: CombinePublisherTestCase +private class CombineMapPublisherTests: CombinePublisherTestCase, @unchecked Sendable where Collection: CombineTestCollection, Collection: RealmSubscribable { var collection: Collection! @@ -2171,7 +2171,7 @@ extension Map: CombineTestCollection where Key == String, Value == SwiftObject? } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class ManagedMapPublisherTests: TestCase { +class ManagedMapPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineMapPublisherTests>.testSuite("Map") } @@ -2189,7 +2189,7 @@ extension ModernAllTypesObject: RealmSectionedObject { } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -private class CombineSectionedResultsPublisherTests: CombinePublisherTestCase +private class CombineSectionedResultsPublisherTests: CombinePublisherTestCase, @unchecked Sendable where Collection: CombineTestCollection, Collection: RealmSubscribable, Collection.Element: RealmSectionedObject { var collection: Collection! @@ -3392,7 +3392,7 @@ private class CombineSectionedResultsPublisherTests @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) // swiftlint:disable:next type_name -class ResultsWithSectionedResultsPublisherTests: TestCase { +class ResultsWithSectionedResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineSectionedResultsPublisherTests>.testSuite("Results") } @@ -3400,7 +3400,7 @@ class ResultsWithSectionedResultsPublisherTests: TestCase { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) // swiftlint:disable:next type_name -class ManagedListSectionedResultsPublisherTests: TestCase { +class ManagedListSectionedResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineSectionedResultsPublisherTests>.testSuite("List") } @@ -3408,7 +3408,7 @@ class ManagedListSectionedResultsPublisherTests: TestCase { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) // swiftlint:disable:next type_name -class ManagedMutableSetSectionedResultsPublisherTests: TestCase { +class ManagedMutableSetSectionedResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineSectionedResultsPublisherTests>.testSuite("MutableSet") } @@ -3416,7 +3416,7 @@ class ManagedMutableSetSectionedResultsPublisherTests: TestCase { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) // swiftlint:disable:next type_name -class LinkingObjectsSectionedResultsPublisherTests: TestCase { +class LinkingObjectsSectionedResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineSectionedResultsPublisherTests>.testSuite("LinkingObjects") } @@ -3424,7 +3424,7 @@ class LinkingObjectsSectionedResultsPublisherTests: TestCase { @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) // swiftlint:disable:next type_name -class AnyRealmCollectionSectionedResultsPublisherTests: TestCase { +class AnyRealmCollectionSectionedResultsPublisherTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { return CombineSectionedResultsPublisherTests>.testSuite("AnyRealmCollection") } @@ -3446,7 +3446,7 @@ public final class AltSimpleProjection: Projection, ObjectKeyIdent } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class CombineProjectionPublisherTests: CombinePublisherTestCase { +class CombineProjectionPublisherTests: CombinePublisherTestCase, @unchecked Sendable { var object: SimpleObject! var projection: SimpleProjection! @@ -4080,7 +4080,7 @@ class CombineProjectionPublisherTests: CombinePublisherTestCase { } @available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -class CombineAsyncRealmTests: CombinePublisherTestCase { +class CombineAsyncRealmTests: CombinePublisherTestCase, @unchecked Sendable { func testWillChangeLocalWrite() { let asyncWriteExpectation = expectation(description: "Should complete async write") cancellable = realm.objectWillChange.sink { diff --git a/RealmSwift/Tests/CompactionTests.swift b/RealmSwift/Tests/CompactionTests.swift index 2084a62f62..30c6ab565b 100644 --- a/RealmSwift/Tests/CompactionTests.swift +++ b/RealmSwift/Tests/CompactionTests.swift @@ -34,7 +34,7 @@ private func fileSize(path: String) -> Int { // MARK: Tests -class CompactionTests: TestCase { +class CompactionTests: TestCase, @unchecked Sendable { override func setUp() { super.setUp() autoreleasepool { diff --git a/RealmSwift/Tests/CustomColumnNameTests.swift b/RealmSwift/Tests/CustomColumnNameTests.swift index f3c9f6898c..feb231c9f0 100644 --- a/RealmSwift/Tests/CustomColumnNameTests.swift +++ b/RealmSwift/Tests/CustomColumnNameTests.swift @@ -212,7 +212,7 @@ class EmbeddedCustomObject: EmbeddedObject { // MARK: - Schema Discovery -class CustomColumnNamesSchemaTest: TestCase { +class CustomColumnNamesSchemaTest: TestCase, @unchecked Sendable { func testCustomColumnNameSchema() { let modernCustomObjectSchema = ModernCustomObject().objectSchema for property in modernCustomObjectSchema.properties { @@ -375,7 +375,7 @@ class CustomColumnNamesSchemaTest: TestCase { } } -class CustomColumnModernDynamicObjectTest: TestCase { +class CustomColumnModernDynamicObjectTest: TestCase, @unchecked Sendable { var realm: Realm! override func setUp() { @@ -443,7 +443,7 @@ class CustomColumnModernDynamicObjectTest: TestCase { } } -class CustomColumnTestsBase: TestCase where O.Root == F.Root { +class CustomColumnTestsBase: TestCase, @unchecked Sendable where O.Root == F.Root { var realm: Realm! public var notificationTokens: [NotificationToken] = [] @@ -489,7 +489,7 @@ class CustomColumnTestsBase: CustomColumnTestsBase where O.Root == F.Root, F.ValueType: Equatable { +class CustomColumnResultsTestBase: CustomColumnTestsBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: Equatable { var results: Results! override func setUp() { @@ -503,7 +503,7 @@ class CustomColumnResultsTestBase: CustomColumnResultsTestBase where O.Root == F.Root, F.ValueType: Equatable { +class CustomColumnResultsTest: CustomColumnResultsTestBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: Equatable { // MARK: - Create Object func testCustomColumnResultsCreate() throws { @@ -640,7 +640,7 @@ class CustomColumnResultsTest: CustomColumnResultsTestBase where O.Root == F.Root, F.ValueType: Equatable { +class CustomColumnResultsAggregatesTest: CustomColumnResultsTestBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: Equatable { // MARK: - Aggregates func testCustomColumnResultsAggregateAvg() throws { @@ -698,7 +698,7 @@ class CustomColumnResultsAggregatesTest: CustomColumnResultsTestBase where O.Root == F.Root { +class CustomColumnResultsSectionedTest: CustomColumnResultsTestBase, @unchecked Sendable where O.Root == F.Root { // MARK: - Sectioned func testCustomColumnSectionedResults() throws { @@ -712,7 +712,7 @@ class CustomColumnResultsSectionedTest: CustomColumnTestsBase where O: ObjectBase, O.Root == F.Root, F.ValueType: Equatable { +class CustomColumnObjectTest: CustomColumnTestsBase, @unchecked Sendable where O: ObjectBase, O.Root == F.Root, F.ValueType: Equatable { // MARK: - Subscript func testCustomColumnObjectKVC() throws { @@ -764,7 +764,7 @@ class CustomColumnObjectTest: CustomColumnTestsBase where O: ObjectBase, O.Root == F.Root, F.ValueType: RealmKeyedCollection { +class CustomColumnKeyedObjectTest: CustomColumnTestsBase, @unchecked Sendable where O: ObjectBase, O.Root == F.Root, F.ValueType: RealmKeyedCollection { func testCustomColumnObjectDynamicMap() throws { func testCustomColumnObjectDynamicMap() throws { for (keyPath, count) in F.dynamicMutableSetProperty { @@ -775,7 +775,7 @@ class CustomColumnKeyedObjectTest: CustomColumnTestsBase where O.Root == F.Root, F.ValueType: RealmCollectionValue { +class CustomColumnListTest: CustomColumnTestsBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: RealmCollectionValue { var list: List! override func setUp() { @@ -818,7 +818,7 @@ class CustomColumnListTest: CustomColumnTestsBase where O.Root == F.Root, F.ValueType: RealmCollectionValue { +class CustomColumnSetTest: CustomColumnTestsBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: RealmCollectionValue { var set: MutableSet! override func setUp() { @@ -856,7 +856,7 @@ class CustomColumnSetTest: CustomColumnTestsBase where O.Root == F.Root { +class CustomColumnMapTestBase: CustomColumnTestsBase, @unchecked Sendable where O.Root == F.Root { var map: Map! override func setUp() { @@ -881,7 +881,7 @@ class CustomColumnMapTestBase: CustomColumnMapTestBase where O.Root == F.Root, F.ValueType: Equatable { +class CustomColumnMapTest: CustomColumnMapTestBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: Equatable { // MARK: - ValueForKey func testCustomColumnMapGetValueForKey() throws { @@ -940,7 +940,7 @@ class CustomColumnMapTest: CustomColumnMapTestBase where O.Root == F.Root, F.ValueType: RealmCollectionValue { +class CustomColumnAggregatesMapTest: CustomColumnMapTestBase, @unchecked Sendable where O.Root == F.Root, F.ValueType: RealmCollectionValue { // MARK: - Aggregates func testCustomColumnResultsAggregateAvg() throws { @@ -998,7 +998,7 @@ class CustomColumnAggregatesMapTest [EmbeddedObjectWrapper] { return objectValues().map(EmbeddedObjectWrapper.init) } -class CustomObjectCreationTests: TestCase { +class CustomObjectCreationTests: TestCase, @unchecked Sendable { var rawValues: [String: Any]! var wrappedValues: [String: Any]! var nilOptionalValues: [String: Any]! diff --git a/RealmSwift/Tests/Decimal128Tests.swift b/RealmSwift/Tests/Decimal128Tests.swift index e63ce4982d..1cf41ceeb4 100644 --- a/RealmSwift/Tests/Decimal128Tests.swift +++ b/RealmSwift/Tests/Decimal128Tests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class Decimal128Tests: TestCase { +class Decimal128Tests: TestCase, @unchecked Sendable { // MARK: - Initialization func testDecimal128Initialization() { diff --git a/RealmSwift/Tests/GeospatialTests.swift b/RealmSwift/Tests/GeospatialTests.swift index f3be559059..11c3fa0638 100644 --- a/RealmSwift/Tests/GeospatialTests.swift +++ b/RealmSwift/Tests/GeospatialTests.swift @@ -64,7 +64,7 @@ class PersonLocation: Object { } } -class GeospatialTests: TestCase { +class GeospatialTests: TestCase, @unchecked Sendable { func populatePersonLocationTable() throws { let realm = realmWithTestPath() try realm.write { diff --git a/RealmSwift/Tests/KVOTests.swift b/RealmSwift/Tests/KVOTests.swift index 20194d37ea..ea634daf1b 100644 --- a/RealmSwift/Tests/KVOTests.swift +++ b/RealmSwift/Tests/KVOTests.swift @@ -148,7 +148,7 @@ class SwiftKVOObject: Object { // Most of the testing of KVO functionality is done in the obj-c tests // These tests just verify that it also works on Swift types @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class KVOTests: TestCase { +class KVOTests: TestCase, @unchecked Sendable { var realm: Realm! = nil override func setUp() { @@ -556,7 +556,7 @@ class KVOTests: TestCase { } @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class KVOPersistedTests: KVOTests { +class KVOPersistedTests: KVOTests, @unchecked Sendable { override func getObject(_ obj: SwiftKVOObject) -> (SwiftKVOObject, SwiftKVOObject) { realm.add(obj) return (obj, obj) @@ -564,7 +564,7 @@ class KVOPersistedTests: KVOTests { } @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class KVOMultipleAccessorsTests: KVOTests { +class KVOMultipleAccessorsTests: KVOTests, @unchecked Sendable { override func getObject(_ obj: SwiftKVOObject) -> (SwiftKVOObject, SwiftKVOObject) { realm.add(obj) return (obj, realm.object(ofType: SwiftKVOObject.self, forPrimaryKey: obj.pk)!) diff --git a/RealmSwift/Tests/KeyPathTests.swift b/RealmSwift/Tests/KeyPathTests.swift index 57c8a0f08e..c6cf112c80 100644 --- a/RealmSwift/Tests/KeyPathTests.swift +++ b/RealmSwift/Tests/KeyPathTests.swift @@ -20,7 +20,7 @@ import XCTest import RealmSwift import Foundation -class KeyPathTests: TestCase { +class KeyPathTests: TestCase, @unchecked Sendable { func testModernObjectTopLevel() { XCTAssertEqual(_name(for: \ModernAllTypesObject.pk), "pk") diff --git a/RealmSwift/Tests/ListTests.swift b/RealmSwift/Tests/ListTests.swift index e15bf7eb03..617e4e2a38 100644 --- a/RealmSwift/Tests/ListTests.swift +++ b/RealmSwift/Tests/ListTests.swift @@ -23,7 +23,7 @@ import RealmSwift import RealmSwiftTestSupport #endif -class ListTests: TestCase { +class ListTests: TestCase, @unchecked Sendable { var str1: SwiftStringObject? var str2: SwiftStringObject? var arrayObject: SwiftArrayPropertyObject! @@ -661,7 +661,7 @@ class ListTests: TestCase { } } -class ListStandaloneTests: ListTests { +class ListStandaloneTests: ListTests, @unchecked Sendable { override func createArray() -> SwiftArrayPropertyObject { let array = SwiftArrayPropertyObject() XCTAssertNil(array.realm) @@ -679,7 +679,7 @@ class ListStandaloneTests: ListTests { } } -class ListNewlyAddedTests: ListTests { +class ListNewlyAddedTests: ListTests, @unchecked Sendable { override func createArray() -> SwiftArrayPropertyObject { let array = SwiftArrayPropertyObject() array.name = "name" @@ -708,7 +708,7 @@ class ListNewlyAddedTests: ListTests { } } -class ListNewlyCreatedTests: ListTests { +class ListNewlyCreatedTests: ListTests, @unchecked Sendable { override func createArray() -> SwiftArrayPropertyObject { let realm = realmWithTestPath() realm.beginWrite() @@ -737,7 +737,7 @@ class ListNewlyCreatedTests: ListTests { } } -class ListRetrievedTests: ListTests { +class ListRetrievedTests: ListTests, @unchecked Sendable { override func createArray() -> SwiftArrayPropertyObject { let realm = realmWithTestPath() realm.beginWrite() @@ -770,7 +770,7 @@ class ListRetrievedTests: ListTests { } /// Ensure the range replaceable collection methods behave correctly when emulated for Swift 4 and later. -class ListRRCMethodsTests: TestCase { +class ListRRCMethodsTests: TestCase, @unchecked Sendable { private func compare(array: [Int], with list: List) { guard array.count == list.count else { XCTFail("Array and list have different sizes (\(array.count) and \(list.count), respectively).") diff --git a/RealmSwift/Tests/MapTests.swift b/RealmSwift/Tests/MapTests.swift index fb43509098..58bbed4ef8 100644 --- a/RealmSwift/Tests/MapTests.swift +++ b/RealmSwift/Tests/MapTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class MapTests: TestCase { +class MapTests: TestCase, @unchecked Sendable { var str1: SwiftStringObject! var str2: SwiftStringObject! var realm: Realm! @@ -1031,7 +1031,7 @@ class MapTests: TestCase { } } -class MapStandaloneTests: MapTests { +class MapStandaloneTests: MapTests, @unchecked Sendable { override func createMap() -> Map { return createMapObject().map } @@ -1088,7 +1088,7 @@ class MapStandaloneTests: MapTests { } } -class MapNewlyAddedTests: MapTests { +class MapNewlyAddedTests: MapTests, @unchecked Sendable { override func createMap() -> Map { let mapObj = SwiftMapPropertyObject() realm.add(mapObj) @@ -1111,7 +1111,7 @@ class MapNewlyAddedTests: MapTests { } } -class MapNewlyCreatedTests: MapTests { +class MapNewlyCreatedTests: MapTests, @unchecked Sendable { override func createMap() -> Map { let mapObj = realm.create(SwiftMapPropertyObject.self, value: ["name"]) try! realm.commitWrite() @@ -1133,7 +1133,7 @@ class MapNewlyCreatedTests: MapTests { } } -class MapRetrievedTests: MapTests { +class MapRetrievedTests: MapTests, @unchecked Sendable { override func createMap() -> Map { realm.create(SwiftMapPropertyObject.self, value: ["name"]) try! realm.commitWrite() diff --git a/RealmSwift/Tests/MigrationTests.swift b/RealmSwift/Tests/MigrationTests.swift index be414e1965..1f0a02fb8e 100644 --- a/RealmSwift/Tests/MigrationTests.swift +++ b/RealmSwift/Tests/MigrationTests.swift @@ -44,7 +44,7 @@ private func dynamicRealm(_ fileURL: URL) -> RLMRealm { return try! RLMRealm(configuration: config) } -class MigrationTests: TestCase { +class MigrationTests: TestCase, @unchecked Sendable { private func createDefaultRealm() throws { let config = Realm.Configuration(fileURL: defaultRealmURL()) try autoreleasepool { diff --git a/RealmSwift/Tests/MixedCollectionTest.swift b/RealmSwift/Tests/MixedCollectionTest.swift index 4c62c6ce23..93ef8c9773 100644 --- a/RealmSwift/Tests/MixedCollectionTest.swift +++ b/RealmSwift/Tests/MixedCollectionTest.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class MixedCollectionTest: TestCase { +class MixedCollectionTest: TestCase, @unchecked Sendable { func testAnyMixedDictionary() throws { let so = SwiftStringObject() so.stringCol = "hello" diff --git a/RealmSwift/Tests/ModernKVOTests.swift b/RealmSwift/Tests/ModernKVOTests.swift index 0d8ca9afc6..06b152f873 100644 --- a/RealmSwift/Tests/ModernKVOTests.swift +++ b/RealmSwift/Tests/ModernKVOTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class ModernKVOTests: TestCase { +class ModernKVOTests: TestCase, @unchecked Sendable { var realm: Realm! = nil override func setUp() { @@ -390,14 +390,14 @@ class ModernKVOTests: TestCase { } } -class ModernKVOPersistedTests: ModernKVOTests { +class ModernKVOPersistedTests: ModernKVOTests, @unchecked Sendable { override func getObject(_ obj: ModernAllTypesObject) -> (ModernAllTypesObject, ModernAllTypesObject) { realm.add(obj) return (obj, obj) } } -class ModernKVOMultipleAccessorsTests: ModernKVOTests { +class ModernKVOMultipleAccessorsTests: ModernKVOTests, @unchecked Sendable { override func getObject(_ obj: ModernAllTypesObject) -> (ModernAllTypesObject, ModernAllTypesObject) { realm.add(obj) return (obj, realm.object(ofType: ModernAllTypesObject.self, forPrimaryKey: obj.pk)!) diff --git a/RealmSwift/Tests/ModernObjectAccessorTests.swift b/RealmSwift/Tests/ModernObjectAccessorTests.swift index 28df3858dd..391337d249 100644 --- a/RealmSwift/Tests/ModernObjectAccessorTests.swift +++ b/RealmSwift/Tests/ModernObjectAccessorTests.swift @@ -21,7 +21,7 @@ import Realm.Private import RealmSwift import Foundation -class ModernObjectAccessorTests: TestCase { +class ModernObjectAccessorTests: TestCase, @unchecked Sendable { let data = "b".data(using: .utf8, allowLossyConversion: false)! let date = Date(timeIntervalSinceReferenceDate: 2) let oid1 = ObjectId("1234567890ab1234567890ab") diff --git a/RealmSwift/Tests/ModernObjectCreationTests.swift b/RealmSwift/Tests/ModernObjectCreationTests.swift index a4884c1131..01ff9d00f3 100644 --- a/RealmSwift/Tests/ModernObjectCreationTests.swift +++ b/RealmSwift/Tests/ModernObjectCreationTests.swift @@ -20,7 +20,7 @@ import XCTest import RealmSwift import Realm.Private -class ModernObjectCreationTests: TestCase { +class ModernObjectCreationTests: TestCase, @unchecked Sendable { var values: [String: Any]! override func setUp() { values = [ @@ -937,7 +937,7 @@ private func mapValues(_ values: [T]) -> [String: T] { return map } -class ModernEnumObjectCreationTests: TestCase { +class ModernEnumObjectCreationTests: TestCase, @unchecked Sendable { let values: [String: Any] = [ "listInt": EnumInt.values(), "listInt8": EnumInt8.values(), diff --git a/RealmSwift/Tests/ModernObjectTests.swift b/RealmSwift/Tests/ModernObjectTests.swift index 131841bde2..2ff0b3c139 100644 --- a/RealmSwift/Tests/ModernObjectTests.swift +++ b/RealmSwift/Tests/ModernObjectTests.swift @@ -34,7 +34,7 @@ class ModernDynamicDefaultObject: Object { @Persisted var binaryCol = UUID().uuidString.data(using: .utf8) } -class ModernObjectTests: TestCase { +class ModernObjectTests: TestCase, @unchecked Sendable { // init() Tests are in ObjectCreationTests.swift // init(value:) tests are in ObjectCreationTests.swift diff --git a/RealmSwift/Tests/MutableSetTests.swift b/RealmSwift/Tests/MutableSetTests.swift index 03845ce3ee..e2f582deaa 100644 --- a/RealmSwift/Tests/MutableSetTests.swift +++ b/RealmSwift/Tests/MutableSetTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class MutableSetTests: TestCase { +class MutableSetTests: TestCase, @unchecked Sendable { var str1: SwiftStringObject? var str2: SwiftStringObject? var str3: SwiftStringObject? @@ -485,7 +485,7 @@ class MutableSetTests: TestCase { } } -class MutableSetStandaloneTests: MutableSetTests { +class MutableSetStandaloneTests: MutableSetTests, @unchecked Sendable { override func createSet() -> SwiftMutableSetPropertyObject { let set = SwiftMutableSetPropertyObject() XCTAssertNil(set.realm) @@ -499,7 +499,7 @@ class MutableSetStandaloneTests: MutableSetTests { } } -class MutableSetNewlyAddedTests: MutableSetTests { +class MutableSetNewlyAddedTests: MutableSetTests, @unchecked Sendable { override func createSet() -> SwiftMutableSetPropertyObject { let set = SwiftMutableSetPropertyObject() set.name = "name" @@ -520,7 +520,7 @@ class MutableSetNewlyAddedTests: MutableSetTests { } } -class MutableSetNewlyCreatedTests: MutableSetTests { +class MutableSetNewlyCreatedTests: MutableSetTests, @unchecked Sendable { override func createSet() -> SwiftMutableSetPropertyObject { let realm = realmWithTestPath() realm.beginWrite() @@ -542,7 +542,7 @@ class MutableSetNewlyCreatedTests: MutableSetTests { } } -class MutableSetRetrievedTests: MutableSetTests { +class MutableSetRetrievedTests: MutableSetTests, @unchecked Sendable { override func createSet() -> SwiftMutableSetPropertyObject { let realm = realmWithTestPath() realm.beginWrite() diff --git a/RealmSwift/Tests/ObjectAccessorTests.swift b/RealmSwift/Tests/ObjectAccessorTests.swift index bd9e0b3de0..a2235579f1 100644 --- a/RealmSwift/Tests/ObjectAccessorTests.swift +++ b/RealmSwift/Tests/ObjectAccessorTests.swift @@ -22,7 +22,7 @@ import RealmSwift import Foundation @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class ObjectAccessorTests: TestCase { +class ObjectAccessorTests: TestCase, @unchecked Sendable { func setAndTestAllPropertiesViaNormalAccess(_ object: SwiftObject, _ optObject: SwiftOptionalObject) { object.boolCol = true XCTAssertEqual(object.boolCol, true) diff --git a/RealmSwift/Tests/ObjectCreationTests.swift b/RealmSwift/Tests/ObjectCreationTests.swift index c6c6e2fcc1..d29770de04 100644 --- a/RealmSwift/Tests/ObjectCreationTests.swift +++ b/RealmSwift/Tests/ObjectCreationTests.swift @@ -32,7 +32,7 @@ class ObjectWithPrivateOptionals: Object { } @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class ObjectCreationTests: TestCase { +class ObjectCreationTests: TestCase, @unchecked Sendable { // MARK: - Init tests func testInitWithDefaults() { diff --git a/RealmSwift/Tests/ObjectCustomPropertiesTests.swift b/RealmSwift/Tests/ObjectCustomPropertiesTests.swift index 02d468a27c..8e14b1b4d3 100644 --- a/RealmSwift/Tests/ObjectCustomPropertiesTests.swift +++ b/RealmSwift/Tests/ObjectCustomPropertiesTests.swift @@ -20,7 +20,7 @@ import XCTest import Realm @_spi(RealmSwiftPrivate) import RealmSwift -final class ObjectCustomPropertiesTests: TestCase { +final class ObjectCustomPropertiesTests: TestCase, @unchecked Sendable { override func tearDown() { super.tearDown() CustomPropertiesObject.injected_customRealmProperties = nil diff --git a/RealmSwift/Tests/ObjectIdTests.swift b/RealmSwift/Tests/ObjectIdTests.swift index 68b63e8435..cb9932b568 100644 --- a/RealmSwift/Tests/ObjectIdTests.swift +++ b/RealmSwift/Tests/ObjectIdTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class ObjectIdTests: TestCase { +class ObjectIdTests: TestCase, @unchecked Sendable { func testObjectIdInitialization() { let strValue = "000123450000ffbeef91906c" diff --git a/RealmSwift/Tests/ObjectSchemaInitializationTests.swift b/RealmSwift/Tests/ObjectSchemaInitializationTests.swift index b1be6656d6..65ae4b9e5f 100644 --- a/RealmSwift/Tests/ObjectSchemaInitializationTests.swift +++ b/RealmSwift/Tests/ObjectSchemaInitializationTests.swift @@ -28,7 +28,7 @@ import Foundation #endif @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class ObjectSchemaInitializationTests: TestCase { +class ObjectSchemaInitializationTests: TestCase, @unchecked Sendable { func testAllValidTypes() { let object = SwiftObject() let objectSchema = object.objectSchema @@ -806,6 +806,7 @@ class SwiftObjectWithNonOptionalLinkProperty: SwiftFakeObject { @objc dynamic var objectCol = SwiftBoolObject() } +#if compiler(<6) extension Set: RealmOptionalType { public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Set? { fatalError() @@ -815,6 +816,17 @@ extension Set: RealmOptionalType { fatalError() } } +#else +extension Set: @retroactive RealmOptionalType { + public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Set? { + fatalError() + } + + public var _rlmObjcValue: Any { + fatalError() + } +} +#endif @available(*, deprecated) // Silence deprecation warnings for RealmOptional class SwiftObjectWithNonRealmOptionalType: SwiftFakeObject { diff --git a/RealmSwift/Tests/ObjectSchemaTests.swift b/RealmSwift/Tests/ObjectSchemaTests.swift index 6611e7ae19..64d4ae0024 100644 --- a/RealmSwift/Tests/ObjectSchemaTests.swift +++ b/RealmSwift/Tests/ObjectSchemaTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class ObjectSchemaTests: TestCase { +class ObjectSchemaTests: TestCase, @unchecked Sendable { var objectSchema: ObjectSchema! var swiftObjectSchema: ObjectSchema { diff --git a/RealmSwift/Tests/ObjectTests.swift b/RealmSwift/Tests/ObjectTests.swift index 714a1c4655..4668d939dc 100644 --- a/RealmSwift/Tests/ObjectTests.swift +++ b/RealmSwift/Tests/ObjectTests.swift @@ -45,7 +45,7 @@ class SwiftDynamicDefaultObject: Object { } @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class ObjectTests: TestCase { +class ObjectTests: TestCase, @unchecked Sendable { // init() Tests are in ObjectCreationTests.swift // init(value:) tests are in ObjectCreationTests.swift diff --git a/RealmSwift/Tests/ObjectiveCSupportTests.swift b/RealmSwift/Tests/ObjectiveCSupportTests.swift index 9600b5d260..4bf5c22431 100644 --- a/RealmSwift/Tests/ObjectiveCSupportTests.swift +++ b/RealmSwift/Tests/ObjectiveCSupportTests.swift @@ -21,7 +21,7 @@ import Realm import RealmSwift import XCTest -class ObjectiveCSupportTests: TestCase { +class ObjectiveCSupportTests: TestCase, @unchecked Sendable { func testSupport() { diff --git a/RealmSwift/Tests/PerformanceTests.swift b/RealmSwift/Tests/PerformanceTests.swift index e657e78381..93baffef2f 100644 --- a/RealmSwift/Tests/PerformanceTests.swift +++ b/RealmSwift/Tests/PerformanceTests.swift @@ -47,7 +47,7 @@ private var largeRealm: Realm! private let isRunningOnDevice = TARGET_IPHONE_SIMULATOR == 0 @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class SwiftPerformanceTests: TestCase { +class SwiftPerformanceTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { #if !DEBUG && os(iOS) && !targetEnvironment(macCatalyst) if isRunningOnDevice { @@ -932,7 +932,7 @@ class SwiftPerformanceTests: TestCase { } } -class SwiftSyncRealmPerformanceTests: TestCase { +class SwiftSyncRealmPerformanceTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { #if !DEBUG && os(iOS) && !targetEnvironment(macCatalyst) if isRunningOnDevice { @@ -1038,7 +1038,7 @@ class SwiftSyncRealmPerformanceTests: TestCase { } } -class SwiftFlexibleSyncRealmPerformanceTests: SwiftSyncRealmPerformanceTests { +class SwiftFlexibleSyncRealmPerformanceTests: SwiftSyncRealmPerformanceTests, @unchecked Sendable { override var config: Realm.Configuration { var config = ObjectiveCSupport.convert(object: RLMRealmConfiguration.fakeFlexibleSync()) config.objectTypes = [] diff --git a/RealmSwift/Tests/PrimitiveListTests.swift b/RealmSwift/Tests/PrimitiveListTests.swift index df88c4b1b2..43a8b4e2ca 100644 --- a/RealmSwift/Tests/PrimitiveListTests.swift +++ b/RealmSwift/Tests/PrimitiveListTests.swift @@ -499,7 +499,7 @@ func addTests(_ suite: XCTestSuite, _ type: OF.Type) { AddablePrimitiveListTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedPrimitiveListTests: TestCase { +class UnmanagedPrimitiveListTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged Primitive Lists") addTests(suite, UnmanagedObjectFactory.self) @@ -507,7 +507,7 @@ class UnmanagedPrimitiveListTests: TestCase { } } -class ManagedPrimitiveListTests: TestCase { +class ManagedPrimitiveListTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed Primitive Lists") addTests(suite, ManagedObjectFactory.self) diff --git a/RealmSwift/Tests/PrimitiveMapTests.swift b/RealmSwift/Tests/PrimitiveMapTests.swift index 146232171e..ba03762ce6 100644 --- a/RealmSwift/Tests/PrimitiveMapTests.swift +++ b/RealmSwift/Tests/PrimitiveMapTests.swift @@ -22,7 +22,7 @@ import RealmSwift // swiftlint:disable cyclomatic_complexity -class PrimitiveMapTestsBase: TestCase { +class PrimitiveMapTestsBase: TestCase, @unchecked Sendable { var realm: Realm? var obj: V.MapRoot! var obj2: V.MapRoot! @@ -49,7 +49,7 @@ class PrimitiveMapTestsBase: TestCase { } } -class PrimitiveMapTests: PrimitiveMapTestsBase { +class PrimitiveMapTests: PrimitiveMapTestsBase, @unchecked Sendable { func testInvalidated() { XCTAssertFalse(map.isInvalidated) if let realm = obj.realm { @@ -179,7 +179,7 @@ class PrimitiveMapTests: PrimitiveMapTests } } -class MinMaxPrimitiveMapTests: PrimitiveMapTestsBase where V.PersistedType: MinMaxType { +class MinMaxPrimitiveMapTests: PrimitiveMapTestsBase, @unchecked Sendable where V.PersistedType: MinMaxType { func testMin() { XCTAssertNil(map.min()) map.merge(values) { $1 } @@ -194,7 +194,7 @@ class MinMaxPrimitiveMapTests: PrimitiveMa } } -class AddablePrimitiveMapTests: PrimitiveMapTestsBase where V: NumericValueFactory, V.PersistedType: AddableType { +class AddablePrimitiveMapTests: PrimitiveMapTestsBase, @unchecked Sendable where V: NumericValueFactory, V.PersistedType: AddableType { func testSum() { XCTAssertEqual(map.sum(), .zero) map.merge(values) { $1 } @@ -208,7 +208,7 @@ class AddablePrimitiveMapTests: PrimitiveM } } -class SortablePrimitiveMapTests: PrimitiveMapTestsBase where V.PersistedType: SortableType { +class SortablePrimitiveMapTests: PrimitiveMapTestsBase, @unchecked Sendable where V.PersistedType: SortableType { func testSorted() { map.merge(values) { $1 } XCTAssertEqual(map.count, 3) @@ -324,7 +324,7 @@ func addPrimitiveMapTests(_ suite: XCTestSuite, _ type: OF.Ty MinMaxPrimitiveMapTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedPrimitiveMapTests: TestCase { +class UnmanagedPrimitiveMapTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged Primitive Maps") addPrimitiveMapTests(suite, UnmanagedObjectFactory.self) @@ -332,7 +332,7 @@ class UnmanagedPrimitiveMapTests: TestCase { } } -class ManagedPrimitiveMapTests: TestCase { +class ManagedPrimitiveMapTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed Primitive Maps") addPrimitiveMapTests(suite, ManagedObjectFactory.self) diff --git a/RealmSwift/Tests/PrimitiveMutableSetTests.swift b/RealmSwift/Tests/PrimitiveMutableSetTests.swift index 1c616af6c6..24bd1a0a73 100644 --- a/RealmSwift/Tests/PrimitiveMutableSetTests.swift +++ b/RealmSwift/Tests/PrimitiveMutableSetTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class PrimitiveMutableSetTestsBase: TestCase { +class PrimitiveMutableSetTestsBase: TestCase, @unchecked Sendable { var realm: Realm? var obj: V.SetRoot! var obj2: V.SetRoot! @@ -46,7 +46,7 @@ class PrimitiveMutableSetTestsBase: TestCa } } -class PrimitiveMutableSetTests: PrimitiveMutableSetTestsBase { +class PrimitiveMutableSetTests: PrimitiveMutableSetTestsBase, @unchecked Sendable { func testInvalidated() { XCTAssertFalse(mutableSet.isInvalidated) if let realm = obj.realm { @@ -187,7 +187,7 @@ class PrimitiveMutableSetTests: PrimitiveM } } -class MinMaxPrimitiveMutableSetTests: PrimitiveMutableSetTestsBase where V.PersistedType: MinMaxType { +class MinMaxPrimitiveMutableSetTests: PrimitiveMutableSetTestsBase, @unchecked Sendable where V.PersistedType: MinMaxType { func testMin() { XCTAssertNil(mutableSet.min()) mutableSet.insert(objectsIn: values) @@ -201,7 +201,7 @@ class MinMaxPrimitiveMutableSetTests: Prim } } -class AddablePrimitiveMutableSetTests: PrimitiveMutableSetTestsBase where V: NumericValueFactory, V.PersistedType: AddableType { +class AddablePrimitiveMutableSetTests: PrimitiveMutableSetTestsBase, @unchecked Sendable where V: NumericValueFactory, V.PersistedType: AddableType { func testSum() { XCTAssertEqual(mutableSet.sum(), .zero) mutableSet.insert(objectsIn: values) @@ -215,7 +215,7 @@ class AddablePrimitiveMutableSetTests: Pri } } -class SortablePrimitiveMutableSetTests: PrimitiveMutableSetTestsBase where V.PersistedType: SortableType { +class SortablePrimitiveMutableSetTests: PrimitiveMutableSetTestsBase, @unchecked Sendable where V.PersistedType: SortableType { func testSorted() { var shuffled = values! shuffled.removeFirst() @@ -329,7 +329,7 @@ func addMutableSetTests(_ suite: XCTestSuite, _ type: OF.Type MinMaxPrimitiveMutableSetTests.defaultTestSuite.tests.forEach(suite.addTest) } -class UnmanagedPrimitiveMutableSetTests: TestCase { +class UnmanagedPrimitiveMutableSetTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Unmanaged Primitive Sets") addMutableSetTests(suite, UnmanagedObjectFactory.self) @@ -337,7 +337,7 @@ class UnmanagedPrimitiveMutableSetTests: TestCase { } } -class ManagedPrimitiveMutableSetTests: TestCase { +class ManagedPrimitiveMutableSetTests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { let suite = XCTestSuite(name: "Managed Primitive Sets") addMutableSetTests(suite, ManagedObjectFactory.self) diff --git a/RealmSwift/Tests/ProjectedCollectTests.swift b/RealmSwift/Tests/ProjectedCollectTests.swift index d418599ade..2b3fda04ca 100644 --- a/RealmSwift/Tests/ProjectedCollectTests.swift +++ b/RealmSwift/Tests/ProjectedCollectTests.swift @@ -30,7 +30,7 @@ class ProjectedCollections: Projection { @Projected(\PersistedCollections.set.projectTo.firstName) var set: ProjectedCollection } -class ProjectedCollectionsTestsTemplate: TestCase { +class ProjectedCollectionsTestsTemplate: TestCase, @unchecked Sendable { // To test some of methods there should be a collection of projections instead of collection of strings // set value in subclass var collection: ProjectedCollection! @@ -300,7 +300,7 @@ class ProjectedCollectionsTestsTemplate: TestCase { } } -class ProjectedListTests: ProjectedCollectionsTestsTemplate { +class ProjectedListTests: ProjectedCollectionsTestsTemplate, @unchecked Sendable { override func setUp() { super.setUp() let realm = realmWithTestPath() @@ -312,7 +312,7 @@ class ProjectedListTests: ProjectedCollectionsTestsTemplate { } } -class ProjectedSetTests: ProjectedCollectionsTestsTemplate { +class ProjectedSetTests: ProjectedCollectionsTestsTemplate, @unchecked Sendable { override func setUp() { super.setUp() let realm = realmWithTestPath() diff --git a/RealmSwift/Tests/ProjectionTests.swift b/RealmSwift/Tests/ProjectionTests.swift index cd27f3fe3d..8bdb5071c8 100644 --- a/RealmSwift/Tests/ProjectionTests.swift +++ b/RealmSwift/Tests/ProjectionTests.swift @@ -251,7 +251,7 @@ public final class MultipleProjectionsFromOneProperty: Projection // MARK: Tests @available(iOS 13.0, *) -class ProjectionTests: TestCase { +class ProjectionTests: TestCase, @unchecked Sendable { func assertSetEquals(_ set: MutableSet, _ expected: Array) { XCTAssertEqual(set.count, Set(expected).count) XCTAssertEqual(Set(set), Set(expected)) @@ -1590,6 +1590,7 @@ class ProjectionTests: TestCase { observeSetChange(obs, "mapOptUuid") { obj.mapOptUuid.removeObject(for: "key") } } + @MainActor func testObserveOnActor() async throws { let projection = simpleProjection() let ex = expectation(description: "got change") diff --git a/RealmSwift/Tests/PropertyTests.swift b/RealmSwift/Tests/PropertyTests.swift index deee163d85..40bf491880 100644 --- a/RealmSwift/Tests/PropertyTests.swift +++ b/RealmSwift/Tests/PropertyTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class PropertyTests: TestCase { +class PropertyTests: TestCase, @unchecked Sendable { var primitiveProperty: Property! var linkProperty: Property! var primaryProperty: Property! diff --git a/RealmSwift/Tests/QueryTests.swift b/RealmSwift/Tests/QueryTests.swift index 15904542d1..a96bb029a9 100644 --- a/RealmSwift/Tests/QueryTests.swift +++ b/RealmSwift/Tests/QueryTests.swift @@ -22,7 +22,7 @@ import RealmSwift // This file is generated from a template. Do not edit directly. // swiftlint:disable large_tuple vertical_parameter_alignment -class QueryTests: TestCase { +class QueryTests: TestCase, @unchecked Sendable { private var realm: Realm! // MARK: Test data population diff --git a/RealmSwift/Tests/QueryTests.swift.gyb b/RealmSwift/Tests/QueryTests.swift.gyb index 4bbcfb4db0..2eb6fa5480 100644 --- a/RealmSwift/Tests/QueryTests.swift.gyb +++ b/RealmSwift/Tests/QueryTests.swift.gyb @@ -234,7 +234,7 @@ import RealmSwift return [list(p) for _, p in itertools.groupby(properties, lambda x: x.className)] }% -class QueryTests: TestCase { +class QueryTests: TestCase, @unchecked Sendable { private var realm: Realm! // MARK: Test data population diff --git a/RealmSwift/Tests/RealmCollectionTypeTests.swift b/RealmSwift/Tests/RealmCollectionTypeTests.swift index 94e2d58f4b..cba8cbb7ca 100644 --- a/RealmSwift/Tests/RealmCollectionTypeTests.swift +++ b/RealmSwift/Tests/RealmCollectionTypeTests.swift @@ -90,7 +90,7 @@ struct Config { SwiftObject.self, SwiftBoolObject.self]) } -class RealmCollectionTests: TestCase where +class RealmCollectionTests: TestCase, @unchecked Sendable where Collection.Element == CTTNullableStringObjectWithLink, Collection.Index == Int, AggregateCollection.Element == CTTAggregateObject, AggregateCollection.Index == Int { var str1: CTTNullableStringObjectWithLink! @@ -1379,7 +1379,7 @@ class RealmCollectionTests, Results> { +class ResultsTests: RealmCollectionTests, Results>, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { // Don't run tests for the base class if isEqual(ResultsTests.self) { @@ -1452,7 +1452,7 @@ class ResultsTests: RealmCollectionTests Results { return realm.objects(CTTNullableStringObjectWithLink.self) } @@ -1609,7 +1609,7 @@ class ResultsFromTableTests: ResultsTests { } } -class ResultsFromTableViewTests: ResultsTests { +class ResultsFromTableViewTests: ResultsTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> Results { return realm.objects(CTTNullableStringObjectWithLink.self).filter("stringCol != ''") } @@ -1620,7 +1620,7 @@ class ResultsFromTableViewTests: ResultsTests { } } -class ResultsFromLinkViewTests: ResultsTests { +class ResultsFromLinkViewTests: ResultsTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> Results { let array = realm.create(CTTStringList.self, value: [[str1, str2]]) return array.array.filter(NSPredicate(value: true)) @@ -1644,7 +1644,7 @@ class ResultsFromLinkViewTests: ResultsTests { // MARK: List -class ListRealmCollectionTests: RealmCollectionTests, List> { +class ListRealmCollectionTests: RealmCollectionTests, List>, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { // Don't run tests for the base class if isEqual(ListRealmCollectionTests.self) { @@ -1659,7 +1659,7 @@ class ListRealmCollectionTests: RealmCollectionTests List { return CTTStringList(value: [[str1, str2]]).array } @@ -1815,7 +1815,7 @@ class ListUnmanagedRealmCollectionTests: ListRealmCollectionTests { override func testQueryFrozenCollection() {} } -class ListNewlyAddedRealmCollectionTests: ListRealmCollectionTests { +class ListNewlyAddedRealmCollectionTests: ListRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> List { let array = CTTStringList(value: [[str1, str2]]) realm.add(array) @@ -1829,7 +1829,7 @@ class ListNewlyAddedRealmCollectionTests: ListRealmCollectionTests { } } -class ListNewlyCreatedRealmCollectionTests: ListRealmCollectionTests { +class ListNewlyCreatedRealmCollectionTests: ListRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> List { realm.create(CTTStringList.self, value: [[str1, str2]]).array } @@ -1840,7 +1840,7 @@ class ListNewlyCreatedRealmCollectionTests: ListRealmCollectionTests { } } -class ListRetrievedRealmCollectionTests: ListRealmCollectionTests { +class ListRetrievedRealmCollectionTests: ListRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> List { _ = realm.create(CTTStringList.self, value: [[str1, str2]]) return realm.objects(CTTStringList.self).first!.array @@ -1855,7 +1855,7 @@ class ListRetrievedRealmCollectionTests: ListRealmCollectionTests { // MARK: MutableSet -class MutableSetRealmCollectionTests: RealmCollectionTests, MutableSet> { +class MutableSetRealmCollectionTests: RealmCollectionTests, MutableSet>, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { // Don't run tests for the base class if isEqual(MutableSetRealmCollectionTests.self) { @@ -1925,7 +1925,7 @@ class MutableSetRealmCollectionTests: RealmCollectionTests MutableSet { return CTTStringSet(value: [[str1, str2]]).set } @@ -2067,7 +2067,7 @@ class MutableSetUnmanagedRealmCollectionTests: MutableSetRealmCollectionTests { override func testQueryFrozenCollection() {} } -class MutableSetNewlyAddedRealmCollectionTests: MutableSetRealmCollectionTests { +class MutableSetNewlyAddedRealmCollectionTests: MutableSetRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> MutableSet { let set = CTTStringSet(value: [[str1, str2]]) realm.add(set) @@ -2081,7 +2081,7 @@ class MutableSetNewlyAddedRealmCollectionTests: MutableSetRealmCollectionTests { } } -class MutableSetNewlyCreatedRealmCollectionTests: MutableSetRealmCollectionTests { +class MutableSetNewlyCreatedRealmCollectionTests: MutableSetRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> MutableSet { realm.create(CTTStringSet.self, value: [[str1, str2]]).set } @@ -2092,7 +2092,7 @@ class MutableSetNewlyCreatedRealmCollectionTests: MutableSetRealmCollectionTests } } -class MutableSetRetrievedRealmCollectionTests: MutableSetRealmCollectionTests { +class MutableSetRetrievedRealmCollectionTests: MutableSetRealmCollectionTests, @unchecked Sendable { override func getCollection(_ realm: Realm) -> MutableSet { _ = realm.create(CTTStringSet.self, value: [[str1, str2]]) return realm.objects(CTTStringSet.self).first!.set @@ -2104,7 +2104,7 @@ class MutableSetRetrievedRealmCollectionTests: MutableSetRealmCollectionTests { return realm.objects(CTTAggregateObjectSet.self).first!.set } } -class LinkingObjectsCollectionTypeTests: RealmCollectionTests, LinkingObjects> { +class LinkingObjectsCollectionTypeTests: RealmCollectionTests, LinkingObjects>, @unchecked Sendable { override func getCollection(_ realm: Realm) -> LinkingObjects { let target = realm.create(CTTLinkTarget.self, value: [0]) for object in realm.objects(CTTNullableStringObjectWithLink.self) { @@ -2128,7 +2128,7 @@ class LinkingObjectsCollectionTypeTests: RealmCollectionTests, AnyRealmCollection> { +class AnyRealmCollectionTests: RealmCollectionTests, AnyRealmCollection>, @unchecked Sendable { override func getCollection(_ realm: Realm) -> AnyRealmCollection { AnyRealmCollection(realm.create(CTTStringList.self, value: [[str1, str2]]).array) } @@ -2171,7 +2171,7 @@ class AnyRealmCollectionTests: RealmCollectionTests(keyPath: KeyPath>, value: T?) { let o = RealmPropertyObject() diff --git a/RealmSwift/Tests/RealmTests.swift b/RealmSwift/Tests/RealmTests.swift index 1da2f85e27..5539141468 100644 --- a/RealmSwift/Tests/RealmTests.swift +++ b/RealmSwift/Tests/RealmTests.swift @@ -30,7 +30,7 @@ import RealmSwiftTestSupport #endif @available(*, deprecated) // Silence deprecation warnings for RealmOptional -class RealmTests: TestCase { +class RealmTests: TestCase, @unchecked Sendable { enum TestError: Error { case intentional } @@ -1642,16 +1642,22 @@ extension RealmTests { @available(macOS 10.15.4, iOS 13.4, tvOS 13.4, watchOS 6.4, *) func testAsyncRefreshOnQueueConfinedRealm() async throws { - @Locked var realm: Realm! + let realm = Locked(wrappedValue: nil) dispatchSyncNewThread { - realm = try! Realm(queue: self.queue) - } - try await assertPreconditionFailure("asyncRefresh() can only be called on main thread or actor-isolated Realms") { - _ = await realm.asyncRefresh() - } - try await assertPreconditionFailure("asyncWrite() can only be called on main thread or actor-isolated Realms") { - _ = try await realm.asyncWrite { } - } + realm.wrappedValue = try! Realm(queue: self.queue) + } + // asyncRefresh() has to be called from a statically isolated context, + // but the test as whole can't be isolated (or the dispatch async breaks), + // and we have to hop to the actor before fork and not after or the child + // crashes before we get to the precondition + try await Task { @MainActor in + try await assertPreconditionFailure("asyncRefresh() can only be called on main thread or actor-isolated Realms") { + _ = await realm.wrappedValue!.asyncRefresh() + } + try await assertPreconditionFailure("asyncWrite() can only be called on main thread or actor-isolated Realms") { + _ = try await realm.wrappedValue!.asyncWrite { } + } + }.value } @MainActor @@ -1894,12 +1900,21 @@ extension RealmTests { static var shared = CustomGlobalActor() } +#if compiler(<6) @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) extension CancellationError: Equatable { public static func == (lhs: CancellationError, rhs: CancellationError) -> Bool { true } } +#else +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +extension CancellationError: @retroactive Equatable { + public static func == (lhs: CancellationError, rhs: CancellationError) -> Bool { + true + } +} +#endif // Helper extension LogLevel { @@ -1930,7 +1945,7 @@ extension LogLevel { } @available(macOS 12.0, watchOS 8.0, iOS 15.0, tvOS 15.0, macCatalyst 15.0, *) -class LoggerTests: TestCase { +class LoggerTests: TestCase, @unchecked Sendable { var logger: Logger! override func setUp() { logger = Logger.shared diff --git a/RealmSwift/Tests/SchemaTests.swift b/RealmSwift/Tests/SchemaTests.swift index 77353533df..93c4b9cabb 100644 --- a/RealmSwift/Tests/SchemaTests.swift +++ b/RealmSwift/Tests/SchemaTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class SchemaTests: TestCase { +class SchemaTests: TestCase, @unchecked Sendable { var schema: Schema! override func setUp() { diff --git a/RealmSwift/Tests/SectionedResultsTests.swift b/RealmSwift/Tests/SectionedResultsTests.swift index 33b2f2879b..722707766b 100644 --- a/RealmSwift/Tests/SectionedResultsTests.swift +++ b/RealmSwift/Tests/SectionedResultsTests.swift @@ -236,7 +236,7 @@ class BaseOptionalPrimitiveSectionedResultsTests Bool { } @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) -class SwiftUITests: TestCase { +class SwiftUITests: TestCase, @unchecked Sendable { override class var defaultTestSuite: XCTestSuite { if hasSwiftUI() { return super.defaultTestSuite diff --git a/RealmSwift/Tests/SwiftUnicodeTests.swift b/RealmSwift/Tests/SwiftUnicodeTests.swift index 67aadcfa64..25e0aa7e96 100644 --- a/RealmSwift/Tests/SwiftUnicodeTests.swift +++ b/RealmSwift/Tests/SwiftUnicodeTests.swift @@ -21,7 +21,7 @@ import RealmSwift let utf8TestString = "值значен™👍☞⎠‱௹♣︎☐▼❒∑⨌⧭иеمرحبا" -class SwiftUnicodeTests: TestCase { +class SwiftUnicodeTests: TestCase, @unchecked Sendable { func testUTF8StringContents() { let realm = realmWithTestPath() diff --git a/RealmSwift/Tests/ThreadSafeReferenceTests.swift b/RealmSwift/Tests/ThreadSafeReferenceTests.swift index 156a067b43..802781b36e 100644 --- a/RealmSwift/Tests/ThreadSafeReferenceTests.swift +++ b/RealmSwift/Tests/ThreadSafeReferenceTests.swift @@ -19,7 +19,7 @@ import XCTest import RealmSwift -class ThreadSafeReferenceTests: TestCase { +class ThreadSafeReferenceTests: TestCase, @unchecked Sendable { /// Resolve a thread-safe reference confirming that you can't resolve it a second time. func assertResolve(_ realm: Realm, _ reference: ThreadSafeReference) -> T? { XCTAssertFalse(reference.isInvalidated) @@ -350,7 +350,7 @@ struct TestThreadSafeWrapperStruct { } // MARK: ThreadSafeWrapperTests -class ThreadSafeWrapperTests: ThreadSafeReferenceTests { +class ThreadSafeWrapperTests: ThreadSafeReferenceTests, @unchecked Sendable { func wrapperStruct() -> TestThreadSafeWrapperStruct { let realm = try! Realm() var stringObj: SwiftStringObject?, intObj: SwiftIntObject? diff --git a/RealmSwift/Util.swift b/RealmSwift/Util.swift index d5b600db09..7a6e29df33 100644 --- a/RealmSwift/Util.swift +++ b/RealmSwift/Util.swift @@ -160,30 +160,43 @@ internal func logRuntimeIssue(_ message: StaticString) { } } +@available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *) @_unavailableFromAsync -internal func assumeOnMainActorExecutor(_ operation: @MainActor () throws -> T, - file: StaticString = #fileID, line: UInt = #line -) rethrows -> T { +internal func assumeOnMainActorExecutor(_ operation: @MainActor () throws -> Void, + file: StaticString = #fileID, line: UInt = #line +) rethrows { +#if compiler(>=5.10) + // This is backdeployable in Xcode 15.3+, but not 15.1 + try MainActor.assumeIsolated(operation) +#else if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { return try MainActor.assumeIsolated(operation) } precondition(Thread.isMainThread, file: file, line: line) return try withoutActuallyEscaping(operation) { fn in - try unsafeBitCast(fn, to: (() throws -> T).self)() + try unsafeBitCast(fn, to: (() throws -> ()).self)() } +#endif } -@_unavailableFromAsync @available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *) -internal func assumeOnActorExecutor(_ actor: A, - _ operation: (isolated A) throws -> T -) rethrows -> T { - if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { - return try actor.assumeIsolated(operation) - } +extension Actor { + @_unavailableFromAsync + internal func invokeIsolated(_ operation: (isolated Self, Arg) throws -> Ret, _ arg: Arg, + file: StaticString = #fileID, line: UInt = #line + ) rethrows -> Ret { +#if compiler(>=5.10) + // This is backdeployable in Xcode 15.3+, but not 15.1 + preconditionIsolated(file: file, line: line) +#else + if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { + preconditionIsolated(file: file, line: line) + } +#endif - return try withoutActuallyEscaping(operation) { fn in - try unsafeBitCast(fn, to: ((A) throws -> T).self)(actor) + return try withoutActuallyEscaping(operation) { fn in + try unsafeBitCast(fn, to: ((Self, Arg) throws -> Ret).self)(self, arg) + } } } diff --git a/dependencies.list b/dependencies.list index 36c8ff300d..aafd0e33d7 100755 --- a/dependencies.list +++ b/dependencies.list @@ -1,3 +1,3 @@ VERSION=10.51.0 -REALM_CORE_VERSION=v14.9.0 +REALM_CORE_VERSION=v14.10.1 STITCH_VERSION=b4f0184c963eed8f6cc5e857fac147bef10966d7 diff --git a/scripts/pr-ci-matrix.rb b/scripts/pr-ci-matrix.rb index b3beb155da..a77799ee75 100755 --- a/scripts/pr-ci-matrix.rb +++ b/scripts/pr-ci-matrix.rb @@ -86,7 +86,7 @@ def action # because they don't care about Xcode versions, while some others are latest-only # because they're particularly slow to run. module Workflows - XCODE_VERSIONS = %w(15.1 15.2 15.3 15.4) + XCODE_VERSIONS = %w(15.1 15.2 15.3 15.4 16\ beta) all = ->(v) { true } latest_only = ->(v) { v == XCODE_VERSIONS.last }