diff --git a/.gitignore b/.gitignore
index daf3d5c3e9..c94428a8d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,7 +31,6 @@ Project.xcodeproj/*
Watch/Watch.xcodeproj/*
AppBundle.xcworkspace/*
*.xcworkspace
-tools/buck
*.xcodeproj
!*_Xcode.xcodeproj
.idea
diff --git a/Config/buck_rule_macros.bzl b/Config/buck_rule_macros.bzl
index 5683196e0d..6ec78c36be 100644
--- a/Config/buck_rule_macros.bzl
+++ b/Config/buck_rule_macros.bzl
@@ -7,7 +7,7 @@ text_section_items = [
"__text",
]
-text_section_rename_linker_flags = ["-Wl,-rename_section,__TEXT,%s,__MEXT,%s" % (name, name) for name in text_section_items] + ["-Wl,-segprot,__MEXT,rx,rx"]
+text_section_rename_linker_flags = [] #["-Wl,-rename_section,__TEXT,%s,__MEXT,%s" % (name, name) for name in text_section_items] + ["-Wl,-segprot,__MEXT,rx,rx"]
section_rename_linker_flags = text_section_rename_linker_flags
diff --git a/Config/configs.bzl b/Config/configs.bzl
index 75fa2d15c3..b3806e01c1 100644
--- a/Config/configs.bzl
+++ b/Config/configs.bzl
@@ -298,6 +298,7 @@ def watch_extension_info_plist_substitutions():
"CURRENT_PROJECT_VERSION": "1",
"BUILD_NUMBER": get_build_number(),
"PRODUCT_BUNDLE_SHORT_VERSION": get_short_version(),
+ "MinimumOSVersion": "5.0",
}
return substitutions
@@ -312,5 +313,6 @@ def watch_info_plist_substitutions():
"CURRENT_PROJECT_VERSION": "1",
"BUILD_NUMBER": get_build_number(),
"PRODUCT_BUNDLE_SHORT_VERSION": get_short_version(),
+ "MinimumOSVersion": "5.0",
}
return substitutions
diff --git a/Makefile b/Makefile
index 565b3215a6..86cb7456a9 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
include Utils.makefile
BUCK_OPTIONS=\
- --config custom.appVersion="5.12.1" \
+ --config custom.appVersion="5.12.2" \
--config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
--config custom.distributionCodeSignIdentity="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
--config custom.developmentTeam="${DEVELOPMENT_TEAM}" \
diff --git a/NotificationContent/Info.plist b/NotificationContent/Info.plist
index daaf0f8756..cedf175e70 100644
--- a/NotificationContent/Info.plist
+++ b/NotificationContent/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
NSExtension
diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist
index 4b49528aad..1c6d112207 100644
--- a/NotificationService/Info.plist
+++ b/NotificationService/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
NSExtension
diff --git a/NotificationService/NotificationService.h b/NotificationService/NotificationService.h
index f8e94caf66..c7b6906685 100644
--- a/NotificationService/NotificationService.h
+++ b/NotificationService/NotificationService.h
@@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface NotificationServiceImpl : NSObject
-- (instancetype)initWithCountIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage isLocked:(bool (^)(NSString *))isLocked lockedMessageText:(NSString *(^)(NSString *))lockedMessageText;
+- (instancetype)initWithSerialDispatch:(void (^)(dispatch_block_t))serialDispatch countIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage isLocked:(bool (^)(NSString *))isLocked lockedMessageText:(NSString *(^)(NSString *))lockedMessageText;
- (void)updateUnreadCount:(int32_t)unreadCount;
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler;
diff --git a/NotificationService/NotificationService.m b/NotificationService/NotificationService.m
index b194d85da2..8d2df09a25 100644
--- a/NotificationService/NotificationService.m
+++ b/NotificationService/NotificationService.m
@@ -51,6 +51,7 @@ static void reportMemory() {
#endif
@interface NotificationServiceImpl () {
+ void (^_serialDispatch)(dispatch_block_t);
void (^_countIncomingMessage)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t);
NSString * _Nullable _rootPath;
@@ -70,13 +71,14 @@ static void reportMemory() {
@implementation NotificationServiceImpl
-- (instancetype)initWithCountIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage isLocked:(nonnull bool (^)(NSString * _Nonnull))isLocked lockedMessageText:(NSString *(^)(NSString *))lockedMessageText {
+- (instancetype)initWithSerialDispatch:(void (^)(dispatch_block_t))serialDispatch countIncomingMessage:(void (^)(NSString *, int64_t, DeviceSpecificEncryptionParameters *, int64_t, int32_t))countIncomingMessage isLocked:(nonnull bool (^)(NSString * _Nonnull))isLocked lockedMessageText:(NSString *(^)(NSString *))lockedMessageText {
self = [super init];
if (self != nil) {
#if DEBUG
reportMemory();
#endif
+ _serialDispatch = [serialDispatch copy];
_countIncomingMessage = [countIncomingMessage copy];
NSString *appBundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
@@ -127,27 +129,32 @@ static void reportMemory() {
reportMemory();
#endif
- #ifdef __IPHONE_13_0
- if (_baseAppBundleId != nil) {
- BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:[_baseAppBundleId stringByAppendingString:@".refresh"]];
- request.earliestBeginDate = nil;
- NSError *error = nil;
- [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
- if (error != nil) {
- NSLog(@"Error: %@", error);
- }
- }
- #endif
+ NSString *baseAppBundleId = _baseAppBundleId;
+ void (^contentHandler)(UNNotificationContent *) = [_contentHandler copy];
+ UNMutableNotificationContent *bestAttemptContent = _bestAttemptContent;
+ NSNumber *updatedUnreadCount = updatedUnreadCount;
- if (_bestAttemptContent && _contentHandler) {
- if (_updatedUnreadCount != nil) {
- int32_t unreadCount = (int32_t)[_updatedUnreadCount intValue];
- if (unreadCount > 0) {
- _bestAttemptContent.badge = @(unreadCount);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ #ifdef __IPHONE_13_0
+ if (baseAppBundleId != nil && false) {
+ BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:[baseAppBundleId stringByAppendingString:@".refresh"]];
+ request.earliestBeginDate = nil;
+ NSError *error = nil;
+ [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
+ if (error != nil) {
+ NSLog(@"Error: %@", error);
}
}
- _contentHandler(_bestAttemptContent);
- }
+ #endif
+
+ if (updatedUnreadCount != nil) {
+ int32_t unreadCount = (int32_t)[updatedUnreadCount intValue];
+ if (unreadCount > 0) {
+ bestAttemptContent.badge = @(unreadCount);
+ }
+ }
+ contentHandler(bestAttemptContent);
+ });
}
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
@@ -219,13 +226,16 @@ static void reportMemory() {
silent = [silentString intValue] != 0;
}
- NSString *attachmentDataString = decryptedPayload[@"attachb64"];
NSData *attachmentData = nil;
id parsedAttachment = nil;
- if ([attachmentDataString isKindOfClass:[NSString class]]) {
- attachmentData = parseBase64(attachmentDataString);
- if (attachmentData != nil) {
- parsedAttachment = parseAttachment(attachmentData);
+
+ if (_isLockedValue) {
+ NSString *attachmentDataString = decryptedPayload[@"attachb64"];
+ if ([attachmentDataString isKindOfClass:[NSString class]]) {
+ attachmentData = parseBase64(attachmentDataString);
+ if (attachmentData != nil) {
+ parsedAttachment = parseAttachment(attachmentData);
+ }
}
}
@@ -317,11 +327,12 @@ static void reportMemory() {
}
_bestAttemptContent.title = title;
if (_isLockedValue) {
+ _bestAttemptContent.title = @"";
_bestAttemptContent.subtitle = @"";
if (_lockedMessageTextValue != nil) {
_bestAttemptContent.body = _lockedMessageTextValue;
} else {
- _bestAttemptContent.body = @"You have a new message";
+ _bestAttemptContent.body = @"^You have a new message";
}
} else {
_bestAttemptContent.subtitle = subtitle;
@@ -334,44 +345,52 @@ static void reportMemory() {
if (_lockedMessageTextValue != nil) {
_bestAttemptContent.body = _lockedMessageTextValue;
} else {
- _bestAttemptContent.body = @"You have a new message";
+ _bestAttemptContent.body = @"^You have a new message";
}
} else {
_bestAttemptContent.body = alert;
}
}
- NSString *threadIdString = aps[@"thread-id"];
- if ([threadIdString isKindOfClass:[NSString class]]) {
- _bestAttemptContent.threadIdentifier = threadIdString;
+ if (_isLockedValue) {
+ _bestAttemptContent.threadIdentifier = @"locked";
+ } else {
+ NSString *threadIdString = aps[@"thread-id"];
+ if ([threadIdString isKindOfClass:[NSString class]]) {
+ _bestAttemptContent.threadIdentifier = threadIdString;
+ }
}
NSString *soundString = aps[@"sound"];
if ([soundString isKindOfClass:[NSString class]]) {
_bestAttemptContent.sound = [UNNotificationSound soundNamed:soundString];
}
- NSString *categoryString = aps[@"category"];
- if ([categoryString isKindOfClass:[NSString class]]) {
- _bestAttemptContent.categoryIdentifier = categoryString;
- if (peerId != 0 && messageId != 0 && parsedAttachment != nil && attachmentData != nil) {
- userInfo[@"peerId"] = @(peerId);
- userInfo[@"messageId.namespace"] = @(0);
- userInfo[@"messageId.id"] = @(messageId);
-
- userInfo[@"media"] = [attachmentData base64EncodedStringWithOptions:0];
-
- if (isExpandableMedia) {
- if ([categoryString isEqualToString:@"r"]) {
- _bestAttemptContent.categoryIdentifier = @"withReplyMedia";
- } else if ([categoryString isEqualToString:@"m"]) {
- _bestAttemptContent.categoryIdentifier = @"withMuteMedia";
+ if (_isLockedValue) {
+ _bestAttemptContent.categoryIdentifier = @"locked";
+ } else {
+ NSString *categoryString = aps[@"category"];
+ if ([categoryString isKindOfClass:[NSString class]]) {
+ _bestAttemptContent.categoryIdentifier = categoryString;
+ if (peerId != 0 && messageId != 0 && parsedAttachment != nil && attachmentData != nil) {
+ userInfo[@"peerId"] = @(peerId);
+ userInfo[@"messageId.namespace"] = @(0);
+ userInfo[@"messageId.id"] = @(messageId);
+
+ userInfo[@"media"] = [attachmentData base64EncodedStringWithOptions:0];
+
+ if (isExpandableMedia) {
+ if ([categoryString isEqualToString:@"r"]) {
+ _bestAttemptContent.categoryIdentifier = @"withReplyMedia";
+ } else if ([categoryString isEqualToString:@"m"]) {
+ _bestAttemptContent.categoryIdentifier = @"withMuteMedia";
+ }
}
}
}
- }
-
- if (accountInfos.accounts.count > 1) {
- if (_bestAttemptContent.title.length != 0 && account.peerName.length != 0) {
- _bestAttemptContent.title = [NSString stringWithFormat:@"%@ → %@", _bestAttemptContent.title, account.peerName];
+
+ if (accountInfos.accounts.count > 1) {
+ if (_bestAttemptContent.title.length != 0 && account.peerName.length != 0) {
+ _bestAttemptContent.title = [NSString stringWithFormat:@"%@ → %@", _bestAttemptContent.title, account.peerName];
+ }
}
}
}
@@ -402,9 +421,11 @@ static void reportMemory() {
} else {
BuildConfig *buildConfig = [[BuildConfig alloc] initWithBaseAppBundleId:_baseAppBundleId];
+ void (^serialDispatch)(dispatch_block_t) = _serialDispatch;
+
__weak typeof(self) weakSelf = self;
_cancelFetch = fetchImage(buildConfig, accountInfos.proxy, account, inputFileLocation, fileDatacenterId, ^(NSData * _Nullable data) {
- dispatch_async(dispatch_get_main_queue(), ^{
+ serialDispatch(^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf == nil) {
return;
diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift
index 410dc9a59b..b40349579e 100644
--- a/NotificationService/NotificationService.swift
+++ b/NotificationService/NotificationService.swift
@@ -1,35 +1,52 @@
import Foundation
import UserNotifications
+import SwiftSignalKit
+
+private let queue = Queue()
@available(iOSApplicationExtension 10.0, *)
@objc(NotificationService)
final class NotificationService: UNNotificationServiceExtension {
- private let impl: NotificationServiceImpl
+ private let impl: QueueLocalObject
override init() {
- var completion: ((Int32) -> Void)?
- self.impl = NotificationServiceImpl(countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in
- SyncProviderImpl.addIncomingMessage(withRootPath: rootPath, accountId: accountId, encryptionParameters: encryptionParameters, peerId: peerId, messageId: messageId, completion: { count in
- completion?(count)
+ self.impl = QueueLocalObject(queue: queue, generate: {
+ var completion: ((Int32) -> Void)?
+ let impl = NotificationServiceImpl(serialDispatch: { f in
+ queue.async {
+ f()
+ }
+ }, countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in
+ SyncProviderImpl.addIncomingMessage(queue: queue, withRootPath: rootPath, accountId: accountId, encryptionParameters: encryptionParameters, peerId: peerId, messageId: messageId, completion: { count in
+ completion?(count)
+ })
+ }, isLocked: { rootPath in
+ return SyncProviderImpl.isLocked(withRootPath: rootPath)
+ }, lockedMessageText: { rootPath in
+ return SyncProviderImpl.lockedMessageText(withRootPath: rootPath)
})
- }, isLocked: { rootPath in
- return SyncProviderImpl.isLocked(withRootPath: rootPath)
- }, lockedMessageText: { rootPath in
- return SyncProviderImpl.lockedMessageText(withRootPath: rootPath)
+
+ completion = { [weak impl] count in
+ queue.async {
+ impl?.updateUnreadCount(count)
+ }
+ }
+
+ return impl
})
super.init()
-
- completion = { [weak self] count in
- self?.impl.updateUnreadCount(count)
- }
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
- self.impl.didReceive(request, withContentHandler: contentHandler)
+ self.impl.with { impl in
+ impl.didReceive(request, withContentHandler: contentHandler)
+ }
}
override func serviceExtensionTimeWillExpire() {
- self.impl.serviceExtensionTimeWillExpire()
+ self.impl.with { impl in
+ impl.serviceExtensionTimeWillExpire()
+ }
}
}
diff --git a/NotificationService/Sync.swift b/NotificationService/Sync.swift
index 9565046ad6..21a93f439b 100644
--- a/NotificationService/Sync.swift
+++ b/NotificationService/Sync.swift
@@ -42,17 +42,17 @@ enum SyncProviderImpl {
}
}
- static func addIncomingMessage(withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: @escaping (Int32) -> Void) {
- Queue.mainQueue().async {
+ static func addIncomingMessage(queue: Queue, withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: @escaping (Int32) -> Void) {
+ queue.async {
let _ = registeredTypes
let sharedBasePath = rootPath + "/accounts-metadata"
let basePath = rootPath + "/" + accountRecordIdPathName(accountId) + "/postbox"
- let sharedValueBox = SqliteValueBox(basePath: sharedBasePath + "/db", queue: Queue.mainQueue(), logger: ValueBoxLoggerImpl(), encryptionParameters: nil, disableCache: true, upgradeProgress: { _ in
+ let sharedValueBox = SqliteValueBox(basePath: sharedBasePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: nil, disableCache: true, upgradeProgress: { _ in
})
- let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: Queue.mainQueue(), logger: ValueBoxLoggerImpl(), encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), disableCache: true, upgradeProgress: { _ in
+ let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), disableCache: true, upgradeProgress: { _ in
})
let metadataTable = MessageHistoryMetadataTable(valueBox: valueBox, table: MessageHistoryMetadataTable.tableSpec(10))
diff --git a/Share/ShareRootController.swift b/Share/ShareRootController.swift
index cd0fd1e4d2..5dac1a0097 100644
--- a/Share/ShareRootController.swift
+++ b/Share/ShareRootController.swift
@@ -6,6 +6,16 @@ import BuildConfig
class ShareRootController: UIViewController {
private var impl: ShareRootControllerImpl?
+ override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
+ super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
+
+ self.modalPresentationStyle = .fullScreen
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
override func loadView() {
super.loadView()
diff --git a/SiriIntents/Info.plist b/SiriIntents/Info.plist
index fab3ba3bdf..9f90fbbb21 100644
--- a/SiriIntents/Info.plist
+++ b/SiriIntents/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
NSExtension
diff --git a/SiriIntentsUI/Base.lproj/MainInterface.storyboard b/SiriIntentsUI/Base.lproj/MainInterface.storyboard
deleted file mode 100644
index 831ee40359..0000000000
--- a/SiriIntentsUI/Base.lproj/MainInterface.storyboard
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SiriIntentsUI/Info.plist b/SiriIntentsUI/Info.plist
deleted file mode 100644
index 2141d9b4bb..0000000000
--- a/SiriIntentsUI/Info.plist
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleDisplayName
- SiriIntentsUI
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- XPC!
- CFBundleShortVersionString
- 1.0
- CFBundleVersion
- 104
- NSExtension
-
- NSExtensionAttributes
-
- IntentsSupported
-
- INSendMessageIntent
-
-
- NSExtensionMainStoryboard
- MainInterface
- NSExtensionPointIdentifier
- com.apple.intents-ui-service
-
-
-
diff --git a/SiriIntentsUI/IntentViewController.swift b/SiriIntentsUI/IntentViewController.swift
deleted file mode 100644
index 9ef77998d7..0000000000
--- a/SiriIntentsUI/IntentViewController.swift
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// IntentViewController.swift
-// SiriIntentsUI
-//
-// Created by Peter on 9/2/16.
-// Copyright © 2016 Telegram. All rights reserved.
-//
-
-import IntentsUI
-
-// As an example, this extension's Info.plist has been configured to handle interactions for INSendMessageIntent.
-// You will want to replace this or add other intents as appropriate.
-// The intents whose interactions you wish to handle must be declared in the extension's Info.plist.
-
-// You can test this example integration by saying things to Siri like:
-// "Send a message using "
-
-class IntentViewController: UIViewController, INUIHostedViewControlling {
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
-
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
-
- // MARK: - INUIHostedViewControlling
-
- // Prepare your view controller for the interaction to handle.
- func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
- // Do configuration here, including preparing views and calculating a desired size for presentation.
-
- if let completion = completion {
- completion(self.desiredSize)
- }
- }
-
- var desiredSize: CGSize {
- //return self.extensionContext!.hostedViewMaximumAllowedSize
- return CGSize()
- }
-
-}
diff --git a/SiriIntentsUI/SiriIntentsUI.entitlements b/SiriIntentsUI/SiriIntentsUI.entitlements
deleted file mode 100644
index 65f2a19d32..0000000000
--- a/SiriIntentsUI/SiriIntentsUI.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- com.apple.security.application-groups
-
- group.org.telegram.Telegram-iOS
-
-
-
diff --git a/Telegram-iOS/Info.plist b/Telegram-iOS/Info.plist
index b7c26bf6dc..f66daefe49 100644
--- a/Telegram-iOS/Info.plist
+++ b/Telegram-iOS/Info.plist
@@ -189,7 +189,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleSignature
????
CFBundleURLTypes
diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings
index 5469d2ece1..0301c0bd41 100644
--- a/Telegram-iOS/en.lproj/Localizable.strings
+++ b/Telegram-iOS/en.lproj/Localizable.strings
@@ -4789,7 +4789,7 @@ Any member of this group will be able to see messages in the channel.";
"Wallet.Info.Send" = "Send";
"Wallet.Info.RefreshErrorTitle" = "No network";
"Wallet.Info.RefreshErrorText" = "Couldn't refresh balance. Please make sure your internet connection is working and try again.";
-"Wallet.Info.RefreshErrorNetworkText" = "The wallet state can not be retrieved at this time. Please try again later.";
+"Wallet.Info.RefreshErrorNetworkText" = "Wallet state can not be retrieved at this time. Please try again later.";
"Wallet.Info.UnknownTransaction" = "Empty Transaction";
"Wallet.Info.TransactionTo" = "to";
"Wallet.Info.TransactionFrom" = "from";
@@ -4820,7 +4820,7 @@ Any member of this group will be able to see messages in the channel.";
"Wallet.Send.Balance" = "Balance: %@";
"Wallet.Send.AmountText" = "Grams to send";
"Wallet.Send.Confirmation" = "Confirmation";
-"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n%2$@?\n\nFees: ~%3$@ grams";
+"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n\n%2$@?\n\nBlockchain fees: ~%3$@ grams";
"Wallet.Send.ConfirmationConfirm" = "Confirm";
"Wallet.Send.Send" = "Send";
"Wallet.Send.OwnAddressAlertTitle" = "Warning";
@@ -4828,8 +4828,9 @@ Any member of this group will be able to see messages in the channel.";
"Wallet.Send.OwnAddressAlertProceed" = "Proceed";
"Wallet.Send.TransactionInProgress" = "Please wait until the current transaction is completed.";
"Wallet.Send.SyncInProgress" = "Please wait while the wallet finishes syncing with the TON Blockchain.";
-"Wallet.Settings.Title" = "Wallet Settings";
-"Wallet.Settings.Configuration" = "Configuration";
+"Wallet.Settings.Title" = "Settings";
+"Wallet.Settings.Configuration" = "Server Settings";
+"Wallet.Settings.ConfigurationInfo" = "Advanced Settings";
"Wallet.Settings.BackupWallet" = "Backup Wallet";
"Wallet.Settings.DeleteWallet" = "Delete Wallet";
"Wallet.Settings.DeleteWalletInfo" = "This will disconnect the wallet from this app. You will be able to restore your wallet using 24 secret words – or import another wallet.\n\nGram Wallets are located in the decentralized TON Blockchain. If you want a wallet to be deleted, simply transfer all the grams from it and leave it empty.";
@@ -4888,7 +4889,7 @@ Any member of this group will be able to see messages in the channel.";
"Wallet.TransactionInfo.OtherFeeInfoUrl" = "Blockchain validators collect a tiny fee for processing your decentralized transactions. [More info]()";
"AppWallet.TransactionInfo.FeeInfoURL" = "https://telegram.org/wallet/fee";
"Wallet.WordCheck.Title" = "Test Time!";
-"Wallet.WordCheck.Text" = "Let’s check that you wrote them down correctly. Please enter words\n**%1$@**, **%2$@** and **%3$@** below:";
+"Wallet.WordCheck.Text" = "Let’s check that you wrote them down correctly. Please enter the words\n**%1$@**, **%2$@** and **%3$@**";
"Wallet.WordCheck.Continue" = "Continue";
"Wallet.WordCheck.IncorrectHeader" = "Incorrect words!";
"Wallet.WordCheck.IncorrectText" = "The secret words you have entered do not match the ones in the list.";
@@ -4924,8 +4925,23 @@ Any member of this group will be able to see messages in the channel.";
"Conversation.WalletRequiredNotNow" = "Not Now";
"Conversation.WalletRequiredSetup" = "Set Up";
-"Wallet.Configuration.Title" = "Configuration";
+"Wallet.Configuration.Title" = "Server Settings";
"Wallet.Configuration.Apply" = "Save";
+"Wallet.Configuration.SourceHeader" = "SOURCE";
+"Wallet.Configuration.SourceURL" = "URL";
+"Wallet.Configuration.SourceJSON" = "JSON";
+"Wallet.Configuration.SourceInfo" = "Using a different configuration allows you to change Lite Server addresses.";
+"Wallet.Configuration.BlockchainIdHeader" = "BLOCKCHAIN ID";
+"Wallet.Configuration.BlockchainIdPlaceholder" = "Blockchain ID";
+"Wallet.Configuration.BlockchainIdInfo" = "This setting is for developers. Change it only if you are working on creating your own TON network.";
+"Wallet.Configuration.ApplyErrorTitle" = "Error";
+"Wallet.Configuration.ApplyErrorTextURLInvalid" = "The URL you have entered is invalid. Please try again.";
+"Wallet.Configuration.ApplyErrorTextURLUnreachable" = "There was an error while downloading configuration from %@\nPlease try again.";
+"Wallet.Configuration.ApplyErrorTextURLInvalidData" = "This blockchain configuration is invalid. Please try again.";
+"Wallet.Configuration.ApplyErrorTextJSONInvalidData" = "This blockchain configuration is invalid. Please try again.";
+"Wallet.Configuration.BlockchainNameChangedTitle" = "Warning";
+"Wallet.Configuration.BlockchainNameChangedText" = "Are you sure you want to change the blockchain ID? You don't need this unless you're testing your own TON network.\n\nIf you proceed, you will need to reconnect your wallet using 24 secret words.";
+"Wallet.Configuration.BlockchainNameChangedProceed" = "Proceed";
"Wallet.CreateInvoice.Title" = "Create Invoice";
@@ -5049,3 +5065,5 @@ Any member of this group will be able to see messages in the channel.";
"WebBrowser.InAppSafari" = "In-App Safari";
"Widget.ApplicationLocked" = "Unlock the app to use the widget";
+
+"Group.ErrorSupergroupConversionNotPossible" = "Sorry, you are a member of too many groups and channels. Please leave some before creating a new one.";
diff --git a/Wallet/BUCK b/Wallet/BUCK
index d5b2d2c414..ec39efa1da 100644
--- a/Wallet/BUCK
+++ b/Wallet/BUCK
@@ -80,13 +80,16 @@ apple_library(
],
deps = [
"//submodules/WalletUI:WalletUI",
+ "//submodules/WalletCore:WalletCore",
"//submodules/BuildConfig:BuildConfig",
+ "//submodules/OverlayStatusController:OverlayStatusController",
]
+ framework_binary_dependencies(framework_dependencies),
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
"$SDKROOT/System/Library/Frameworks/VideoToolbox.framework",
+ "$SDKROOT/System/Library/Frameworks/AVFoundation.framework",
],
)
diff --git a/Wallet/Info.plist b/Wallet/Info.plist
index 4b9bfdcdc4..7646b3381e 100644
--- a/Wallet/Info.plist
+++ b/Wallet/Info.plist
@@ -53,10 +53,10 @@
NSAllowsArbitraryLoads
- NSFaceIDUsageDescription
- For better security, please allow TON Wallet to use your Face ID to authenticate payments.
NSCameraUsageDescription
Please allow TON Wallet access to your camera for scanning QR codes.
+ NSFaceIDUsageDescription
+ For better security, please allow TON Wallet to use your Face ID to authenticate payments.
NSPhotoLibraryUsageDescription
Please allow TON Wallet access to your Photo Stream in case you need to scan a QR code from a picture.
UIDeviceFamily
@@ -75,7 +75,7 @@
UIRequiresPersistentWiFi
UIStatusBarStyle
- UIStatusBarStyleDefault
+ UIStatusBarStyleLightContent
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
diff --git a/Wallet/LaunchScreen.xib b/Wallet/LaunchScreen.xib
index 630fe8c241..2b96224d6f 100644
--- a/Wallet/LaunchScreen.xib
+++ b/Wallet/LaunchScreen.xib
@@ -30,6 +30,14 @@
+
+
+
+
+
+
+
+
@@ -39,4 +47,8 @@
+
+
+
+
diff --git a/Wallet/README.md b/Wallet/README.md
new file mode 100644
index 0000000000..792e3695d6
--- /dev/null
+++ b/Wallet/README.md
@@ -0,0 +1,63 @@
+# Test Gram Wallet (iOS)
+
+This is the source code and build instructions for a TON Testnet Wallet implementation for iOS.
+
+1. Install Xcode 11.1
+```
+https://apps.apple.com/ae/app/xcode/id497799835?mt=12
+```
+
+Make sure to launch Xcode at least once and set up command-line tools paths (Xcode — Preferences — Locations — Command Line Tools)
+
+2. Install Homebrew
+
+```
+/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+3. Install the required tools
+
+```
+brew tap AdoptOpenJDK/openjdk
+brew cask install adoptopenjdk8
+brew install cmake ant
+```
+
+4. Build Buck
+
+```
+mkdir -p $HOME/buck_source
+cd tools/buck
+sh ./prepare_buck_source.sh $HOME/buck_source
+```
+
+5. Now you can build Wallet application (IPA)
+
+Note:
+It is recommended to use an artifact cache to optimize build speed. Prepend any of the following commands with
+```
+BUCK_DIR_CACHE="path/to/existing/directory"
+```
+
+```
+BUCK="$HOME/buck_source/buck/buck-out/gen/programs/buck.pex" \
+ BUILD_NUMBER=30 \
+ DISTRIBUTION_CODE_SIGN_IDENTITY="iPhone Distribution: XXXXXXX (XXXXXXXXXX)" \
+ DEVELOPMENT_TEAM="XXXXXXXXXX" WALLET_BUNDLE_ID="wallet.bundle.id" \
+ WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP="wallet distribution provisioning profile name" \
+ CODESIGNING_SOURCE_DATA_PATH="$HOME/wallet_codesigning" \
+ sh Wallet/example_wallet_env.sh make -f Wallet.makefile wallet_app
+```
+
+6. If needed, generate Xcode project
+```
+BUCK="$HOME/buck_source/buck/buck-out/gen/programs/buck.pex" \
+ BUILD_NUMBER=30 \
+ DEVELOPMENT_CODE_SIGN_IDENTITY="iPhone Developer: XXXXXXX (XXXXXXXXXX)" \
+ DISTRIBUTION_CODE_SIGN_IDENTITY="iPhone Distribution: XXXXXXX (XXXXXXXXXX)" \
+ DEVELOPMENT_TEAM="XXXXXXXXXX" WALLET_BUNDLE_ID="wallet.bundle.id" \
+ WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP="wallet development provisioning profile name" \
+ WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP="wallet distribution provisioning profile name" \
+ CODESIGNING_SOURCE_DATA_PATH="$HOME/wallet_codesigning" \
+ sh Wallet/example_wallet_env.sh make -f Wallet.makefile wallet_project
+```
+
diff --git a/Wallet/Sources/AppDelegate.swift b/Wallet/Sources/AppDelegate.swift
index ec44936f4b..ac2c91804b 100644
--- a/Wallet/Sources/AppDelegate.swift
+++ b/Wallet/Sources/AppDelegate.swift
@@ -1,5 +1,6 @@
import UIKit
import Display
+import OverlayStatusController
import SwiftSignalKit
import BuildConfig
import WalletUI
@@ -334,7 +335,10 @@ private final class WalletStorageInterfaceImpl: WalletStorageInterface {
}
private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
- let storage: WalletStorageInterface
+ var storage: WalletStorageInterface {
+ return self.storageImpl
+ }
+ private let storageImpl: WalletStorageInterfaceImpl
let tonInstance: TonInstance
let keychain: TonKeychain
let presentationData: WalletPresentationData
@@ -354,6 +358,23 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
return .single(Data())
}
+ func downloadFile(url: URL) -> Signal {
+ return download(url: url)
+ |> mapError { _ in
+ return .generic
+ }
+ }
+
+ func updateResolvedWalletConfiguration(source: LocalWalletConfigurationSource, blockchainName: String, resolvedValue: String) -> Signal {
+ return self.storageImpl.updateMergedLocalWalletConfiguration { configuration in
+ var configuration = configuration
+ configuration.configuration.source = source
+ configuration.configuration.blockchainName = blockchainName
+ configuration.resolved = ResolvedLocalWalletConfiguration(source: source, value: resolvedValue)
+ return configuration
+ }
+ }
+
func presentNativeController(_ controller: UIViewController) {
self.window.presentNative(controller)
}
@@ -417,9 +438,9 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
picker.presentingViewController?.dismiss(animated: true, completion: nil)
}
- init(basePath: String, storage: WalletStorageInterfaceImpl, config: String, blockchainName: String, navigationBarTheme: NavigationBarTheme, window: Window1) {
+ init(basePath: String, storage: WalletStorageInterfaceImpl, config: String, blockchainName: String, presentationData: WalletPresentationData, navigationBarTheme: NavigationBarTheme, window: Window1) {
let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: basePath + "/keys"), withIntermediateDirectories: true, attributes: nil)
- self.storage = storage
+ self.storageImpl = storage
self.window = window
@@ -481,8 +502,42 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
}
})
#endif
+
+ self.presentationData = presentationData
+
+ super.init()
+ }
+}
+
+@objc(AppDelegate)
+final class AppDelegate: NSObject, UIApplicationDelegate {
+ var window: UIWindow?
+
+ private var mainWindow: Window1?
+ private var walletContext: WalletContextImpl?
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
+ let statusBarHost = ApplicationStatusBarHost()
+ let (window, hostView) = nativeWindowHostView()
+ let mainWindow = Window1(hostView: hostView, statusBarHost: statusBarHost)
+ self.mainWindow = mainWindow
+ hostView.containerView.backgroundColor = UIColor.white
+ self.window = window
+
let accentColor = UIColor(rgb: 0x007ee5)
- self.presentationData = WalletPresentationData(
+
+ let navigationBarTheme = NavigationBarTheme(
+ buttonColor: accentColor,
+ disabledButtonColor: UIColor(rgb: 0xd0d0d0),
+ primaryTextColor: .black,
+ backgroundColor: UIColor(rgb: 0xf7f7f7),
+ separatorColor: UIColor(rgb: 0xb1b1b1),
+ badgeBackgroundColor: UIColor(rgb: 0xff3b30),
+ badgeStrokeColor: UIColor(rgb: 0xff3b30),
+ badgeTextColor: .white
+ )
+
+ let presentationData = WalletPresentationData(
theme: WalletTheme(
info: WalletInfoTheme(
buttonBackgroundColor: accentColor,
@@ -566,37 +621,6 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
)
)
- super.init()
- }
-}
-
-@objc(AppDelegate)
-final class AppDelegate: NSObject, UIApplicationDelegate {
- var window: UIWindow?
-
- private var mainWindow: Window1?
- private var walletContext: WalletContextImpl?
-
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
- let statusBarHost = ApplicationStatusBarHost()
- let (window, hostView) = nativeWindowHostView()
- let mainWindow = Window1(hostView: hostView, statusBarHost: statusBarHost)
- self.mainWindow = mainWindow
- hostView.containerView.backgroundColor = UIColor.white
- self.window = window
-
- let accentColor = UIColor(rgb: 0x007ee5)
- let navigationBarTheme = NavigationBarTheme(
- buttonColor: accentColor,
- disabledButtonColor: UIColor(rgb: 0xd0d0d0),
- primaryTextColor: .black,
- backgroundColor: UIColor(rgb: 0xf7f7f7),
- separatorColor: UIColor(rgb: 0xb1b1b1),
- badgeBackgroundColor: UIColor(rgb: 0xff3b30),
- badgeStrokeColor: UIColor(rgb: 0xff3b30),
- badgeTextColor: .white
- )
-
let navigationController = NavigationController(
mode: .single,
theme: NavigationControllerTheme(
@@ -608,6 +632,8 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
mainWindow.viewController = navigationController
+ navigationController.setViewControllers([WalletApplicationSplashScreen(theme: presentationData.theme)], animated: false)
+
self.window?.makeKeyAndVisible()
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
@@ -634,7 +660,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
guard let parsedUrl = URL(string: url) else {
return .complete()
}
- return downloadFile(url: parsedUrl)
+ return download(url: parsedUrl)
|> retry(1.0, maxDelay: 5.0, onQueue: .mainQueue())
|> mapToSignal { data -> Signal<(ResolvedLocalWalletConfiguration, String), NoError> in
if let string = String(data: data, encoding: .utf8) {
@@ -666,13 +692,38 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
let _ = (resolvedInitialConfig
|> deliverOnMainQueue).start(next: { (initialResolvedConfig, initialConfigBlockchainName) in
- let walletContext = WalletContextImpl(basePath: documentsPath, storage: storage, config: initialResolvedConfig.value, blockchainName: initialConfigBlockchainName, navigationBarTheme: navigationBarTheme, window: mainWindow)
+ let walletContext = WalletContextImpl(basePath: documentsPath, storage: storage, config: initialResolvedConfig.value, blockchainName: initialConfigBlockchainName, presentationData: presentationData, navigationBarTheme: navigationBarTheme, window: mainWindow)
self.walletContext = walletContext
- let _ = (updatedConfigValue
- |> deliverOnMainQueue).start(next: { resolved, blockchainName in
- let _ = walletContext.tonInstance.updateConfig(config: resolved.value, blockchainName: blockchainName).start()
- })
+ let beginWithController: (ViewController) -> Void = { controller in
+ navigationController.setViewControllers([controller], animated: false)
+
+ var previousBlockchainName = initialConfigBlockchainName
+
+ let _ = (updatedConfigValue
+ |> deliverOnMainQueue).start(next: { resolved, blockchainName in
+ let _ = walletContext.tonInstance.validateConfig(config: resolved.value, blockchainName: blockchainName).start(error: { _ in
+ }, completed: {
+ let _ = walletContext.tonInstance.updateConfig(config: resolved.value, blockchainName: blockchainName).start()
+
+ if previousBlockchainName != blockchainName {
+ previousBlockchainName = blockchainName
+
+ let overlayController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
+ mainWindow.present(overlayController, on: .root)
+
+ let _ = (deleteAllLocalWalletsData(storage: walletContext.storage, tonInstance: walletContext.tonInstance)
+ |> deliverOnMainQueue).start(error: { [weak overlayController] _ in
+ overlayController?.dismiss()
+ }, completed: { [weak overlayController] in
+ overlayController?.dismiss()
+
+ navigationController.setViewControllers([WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)], animated: true)
+ })
+ }
+ })
+ })
+ }
let _ = (combineLatest(queue: .mainQueue(),
walletContext.storage.getWalletRecords(),
@@ -681,39 +732,32 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|> deliverOnMainQueue).start(next: { records, publicKey in
if let record = records.first {
if let publicKey = publicKey {
- print("publicKey = \(publicKey.base64EncodedString())")
if record.info.encryptedSecret.publicKey == publicKey {
if record.exportCompleted {
let _ = (walletAddress(publicKey: record.info.publicKey, tonInstance: walletContext.tonInstance)
|> deliverOnMainQueue).start(next: { address in
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: record.info, address: address, enableDebugActions: false)
-
- navigationController.setViewControllers([infoScreen], animated: false)
+ beginWithController(infoScreen)
})
} else {
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(record.info, nil), walletCreatedPreloadState: nil)
-
- navigationController.setViewControllers([createdScreen], animated: false)
+ beginWithController(createdScreen)
}
} else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageReset(.changed), walletCreatedPreloadState: nil)
-
- navigationController.setViewControllers([splashScreen], animated: false)
+ beginWithController(splashScreen)
}
} else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: WalletSplashMode.secureStorageReset(.notAvailable), walletCreatedPreloadState: nil)
-
- navigationController.setViewControllers([splashScreen], animated: false)
+ beginWithController(splashScreen)
}
} else {
if publicKey != nil {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
-
- navigationController.setViewControllers([splashScreen], animated: false)
+ beginWithController(splashScreen)
} else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageNotAvailable, walletCreatedPreloadState: nil)
-
- navigationController.setViewControllers([splashScreen], animated: false)
+ beginWithController(splashScreen)
}
}
})
@@ -727,7 +771,7 @@ private enum DownloadFileError {
case network
}
-private func downloadFile(url: URL) -> Signal {
+private func download(url: URL) -> Signal {
return Signal { subscriber in
let completed = Atomic(value: false)
let downloadTask = URLSession.shared.downloadTask(with: url, completionHandler: { location, _, error in
@@ -761,6 +805,6 @@ struct MergedLocalWalletConfiguration: Codable, Equatable {
private extension MergedLocalWalletConfiguration {
static var `default`: MergedLocalWalletConfiguration {
- return MergedLocalWalletConfiguration(configuration: LocalWalletConfiguration(source: .url("https://test.ton.org/config.json"), blockchainName: "testchain"), resolved: nil)
+ return MergedLocalWalletConfiguration(configuration: LocalWalletConfiguration(source: .url("https://test.ton.org/config.json"), blockchainName: "testnet"), resolved: nil)
}
}
diff --git a/Wallet/Strings/en.lproj/Localizable.strings b/Wallet/Strings/en.lproj/Localizable.strings
index d35e1a7751..1d9c7d939e 100644
--- a/Wallet/Strings/en.lproj/Localizable.strings
+++ b/Wallet/Strings/en.lproj/Localizable.strings
@@ -23,7 +23,7 @@
"Wallet.Info.Send" = "Send";
"Wallet.Info.RefreshErrorTitle" = "No network";
"Wallet.Info.RefreshErrorText" = "Couldn't refresh balance. Please make sure your internet connection is working and try again.";
-"Wallet.Info.RefreshErrorNetworkText" = "The wallet state can not be retrieved at this time. Please try again later.";
+"Wallet.Info.RefreshErrorNetworkText" = "Wallet state can not be retrieved at this time. Please try again later.";
"Wallet.Info.UnknownTransaction" = "Empty Transaction";
"Wallet.Info.TransactionTo" = "to";
"Wallet.Info.TransactionFrom" = "from";
@@ -54,7 +54,7 @@
"Wallet.Send.Balance" = "Balance: %@";
"Wallet.Send.AmountText" = "Grams to send";
"Wallet.Send.Confirmation" = "Confirmation";
-"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n%2$@?\n\nFees: ~%3$@ grams";
+"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n\n%2$@?\n\nBlockchain fees: ~%3$@ grams";
"Wallet.Send.ConfirmationConfirm" = "Confirm";
"Wallet.Send.Send" = "Send";
"Wallet.Send.OwnAddressAlertTitle" = "Warning";
@@ -62,8 +62,9 @@
"Wallet.Send.OwnAddressAlertProceed" = "Proceed";
"Wallet.Send.TransactionInProgress" = "Please wait until the current transaction is completed.";
"Wallet.Send.SyncInProgress" = "Please wait while the wallet finishes syncing with the TON Blockchain.";
-"Wallet.Settings.Title" = "Wallet Settings";
-"Wallet.Settings.Configuration" = "Configuration";
+"Wallet.Settings.Title" = "Settings";
+"Wallet.Settings.Configuration" = "Server Settings";
+"Wallet.Settings.ConfigurationInfo" = "Advanced Settings";
"Wallet.Settings.BackupWallet" = "Backup Wallet";
"Wallet.Settings.DeleteWallet" = "Delete Wallet";
"Wallet.Settings.DeleteWalletInfo" = "This will disconnect the wallet from this app. You will be able to restore your wallet using 24 secret words – or import another wallet.\n\nGram Wallets are located in the decentralized TON Blockchain. If you want a wallet to be deleted, simply transfer all the grams from it and leave it empty.";
@@ -119,7 +120,7 @@
"Wallet.TransactionInfo.OtherFeeInfo" = "Blockchain validators collect a tiny fee for processing your decentralized transactions.";
"Wallet.TransactionInfo.OtherFeeInfoUrl" = "Blockchain validators collect a tiny fee for processing your decentralized transactions. [More info]()";
"Wallet.WordCheck.Title" = "Test Time!";
-"Wallet.WordCheck.Text" = "Let’s check that you wrote them down correctly. Please enter words\n**%1$@**, **%2$@** and **%3$@** below:";
+"Wallet.WordCheck.Text" = "Let’s check that you wrote them down correctly. Please enter the words\n**%1$@**, **%2$@** and **%3$@**";
"Wallet.WordCheck.Continue" = "Continue";
"Wallet.WordCheck.IncorrectHeader" = "Incorrect words!";
"Wallet.WordCheck.IncorrectText" = "The secret words you have entered do not match the ones in the list.";
@@ -149,8 +150,23 @@
"Wallet.Send.SendAnyway" = "Send Anyway";
"Wallet.Receive.CreateInvoice" = "Create Invoice";
"Wallet.Receive.CreateInvoiceInfo" = "You can specify the amount and purpose of the payment to save the sender some time.";
-"Wallet.Configuration.Title" = "Configuration";
+"Wallet.Configuration.Title" = "Server Settings";
"Wallet.Configuration.Apply" = "Save";
+"Wallet.Configuration.SourceHeader" = "SOURCE";
+"Wallet.Configuration.SourceURL" = "URL";
+"Wallet.Configuration.SourceJSON" = "JSON";
+"Wallet.Configuration.SourceInfo" = "Using a different configuration allows you to change Lite Server addresses.";
+"Wallet.Configuration.BlockchainIdHeader" = "BLOCKCHAIN ID";
+"Wallet.Configuration.BlockchainIdPlaceholder" = "Blockchain ID";
+"Wallet.Configuration.BlockchainIdInfo" = "This setting is for developers. Change it only if you are working on creating your own TON network.";
+"Wallet.Configuration.ApplyErrorTitle" = "Error";
+"Wallet.Configuration.ApplyErrorTextURLInvalid" = "The URL you have entered is invalid. Please try again.";
+"Wallet.Configuration.ApplyErrorTextURLUnreachable" = "There was an error while downloading configuration from %@\nPlease try again.";
+"Wallet.Configuration.ApplyErrorTextURLInvalidData" = "This blockchain configuration is invalid. Please try again.";
+"Wallet.Configuration.ApplyErrorTextJSONInvalidData" = "This blockchain configuration is invalid. Please try again.";
+"Wallet.Configuration.BlockchainNameChangedTitle" = "Warning";
+"Wallet.Configuration.BlockchainNameChangedText" = "Are you sure you want to change the blockchain ID? You don't need this unless you're testing your own TON network.\n\nIf you proceed, you will need to reconnect your wallet using 24 secret words.";
+"Wallet.Configuration.BlockchainNameChangedProceed" = "Proceed";
"Wallet.CreateInvoice.Title" = "Create Invoice";
"Wallet.Navigation.Close" = "Close";
"Wallet.Navigation.Back" = "Back";
diff --git a/Wallet/example_wallet_env.sh b/Wallet/example_wallet_env.sh
new file mode 100755
index 0000000000..ed087692a5
--- /dev/null
+++ b/Wallet/example_wallet_env.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+custom_realpath() {
+ OURPWD=$PWD
+ cd "$(dirname "$1")"
+ LINK=$(readlink "$(basename "$1")")
+ while [ "$LINK" ]; do
+ cd "$(dirname "$LINK")"
+ LINK=$(readlink "$(basename "$1")")
+ done
+ REALPATH="$PWD/$(basename "$1")"
+ cd "$OURPWD"
+ echo "$REALPATH"
+}
+
+export TELEGRAM_ENV_SET="1"
+
+export HOCKEYAPP_ID=""
+export IS_INTERNAL_BUILD="false"
+export IS_APPSTORE_BUILD="true"
+export APPSTORE_ID="1"
+export APP_SPECIFIC_URL_SCHEME=""
+export API_ID="0"
+export API_HASH=""
+
+if [ -z "$DEVELOPMENT_CODE_SIGN_IDENTITY" ]; then
+ export DEVELOPMENT_CODE_SIGN_IDENTITY="iPhone Developer: AAAAA AAAAA (XXXXXXXXXX)"
+fi
+if [ -z "$DISTRIBUTION_CODE_SIGN_IDENTITY" ]; then
+ export DISTRIBUTION_CODE_SIGN_IDENTITY="iPhone Distribution: AAAAA AAAAA (XXXXXXXXXX)"
+fi
+if [ -z "$DEVELOPMENT_TEAM" ]; then
+ export DEVELOPMENT_TEAM="XXXXXXXXXX"
+fi
+
+if [ -z "$WALLET_BUNDLE_ID" ]; then
+ export WALLET_BUNDLE_ID="reverse.dns.notation"
+fi
+
+if [ -z "$BUILD_NUMBER" ]; then
+ echo "BUILD_NUMBER is not defined"
+ exit 1
+fi
+
+export WALLET_ENTITLEMENTS_APP="Wallet.entitlements"
+if [ -z "$WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP" ]; then
+ export WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP="development profile name"
+fi
+if [ -z "$WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP" ]; then
+ export WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP="distribution profile name"
+fi
+
+BASE_DIR="$(custom_realpath .)"
+BASE_PATH=$(dirname "$(custom_realpath $0)")
+BUILDBOX_DIR="buildbox"
+
+if [ -z "$CODESIGNING_SOURCE_DATA_PATH" ]; then
+ echo "CODESIGNING_SOURCE_DATA_PATH is not defined"
+ exit 1
+fi
+
+if [ ! -d "$CODESIGNING_SOURCE_DATA_PATH/profiles" ]; then
+ echo "Expected codesigning directory layout:"
+ echo "$CODESIGNING_SOURCE_DATA_PATH/profiles/appstore/*.mobileprovision"
+ exit 1
+fi
+
+rm -rf "$BASE_DIR/$BUILDBOX_DIR/transient-data/teams/$DEVELOPMENT_TEAM/codesigning"
+mkdir -p "$BASE_DIR/$BUILDBOX_DIR/transient-data/teams/$DEVELOPMENT_TEAM/codesigning"
+cp -R "$CODESIGNING_SOURCE_DATA_PATH/"* "$BASE_DIR/$BUILDBOX_DIR/transient-data/teams/$DEVELOPMENT_TEAM/codesigning/"
+
+export CODESIGNING_DATA_PATH="$BUILDBOX_DIR/transient-data/teams/$DEVELOPMENT_TEAM/codesigning"
+export CODESIGNING_CERTS_VARIANT="distribution"
+export CODESIGNING_PROFILES_VARIANT="appstore"
+export PACKAGE_METHOD="appstore"
+
+$@
diff --git a/Watch/App/Info.plist b/Watch/App/Info.plist
index dcf54e58a5..883fc23d8c 100644
--- a/Watch/App/Info.plist
+++ b/Watch/App/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
UIDeviceFamily
diff --git a/Watch/Extension/Info.plist b/Watch/Extension/Info.plist
index 06f504c510..4eb1d3e62e 100644
--- a/Watch/Extension/Info.plist
+++ b/Watch/Extension/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
NSExtension
diff --git a/Widget/Info.plist b/Widget/Info.plist
index 7e87bf7a10..6917b6ac76 100644
--- a/Widget/Info.plist
+++ b/Widget/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 5.12.1
+ $(PRODUCT_BUNDLE_SHORT_VERSION)
CFBundleVersion
${BUILD_NUMBER}
NSExtension
diff --git a/buildbox/buck/buck-2be0e8fa79117daa854e79dd7d9ce32048d506a8.patch b/buildbox/buck/buck-2be0e8fa79117daa854e79dd7d9ce32048d506a8.patch
new file mode 100644
index 0000000000..fe6ee40c41
--- /dev/null
+++ b/buildbox/buck/buck-2be0e8fa79117daa854e79dd7d9ce32048d506a8.patch
@@ -0,0 +1,157 @@
+diff --git a/.gitignore b/.gitignore
+index 78ce658b9a..30c0369ab7 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -3,6 +3,7 @@
+
+ # IntelliJ build
+ /intellij-out/
++/.idea/
+
+ # Buck
+ /buck-out
+diff --git a/.idea/modules.xml b/.idea/modules.xml
+deleted file mode 100644
+index 7ff823b554..0000000000
+--- a/.idea/modules.xml
++++ /dev/null
+@@ -1,16 +0,0 @@
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+\ No newline at end of file
+diff --git a/src/com/facebook/buck/apple/AppleBundle.java b/src/com/facebook/buck/apple/AppleBundle.java
+index d895ab9a79..ad42beb302 100644
+--- a/src/com/facebook/buck/apple/AppleBundle.java
++++ b/src/com/facebook/buck/apple/AppleBundle.java
+@@ -992,7 +992,11 @@ public class AppleBundle extends AbstractBuildRuleWithDeclaredAndExtraDeps
+ keys.put("DTPlatformName", new NSString(platform.getName()));
+ keys.put("DTPlatformVersion", new NSString(sdkVersion));
+ keys.put("DTSDKName", new NSString(sdkName + sdkVersion));
+- keys.put("MinimumOSVersion", new NSString(minOSVersion));
++ if (infoPlistSubstitutions.containsKey("MinimumOSVersion")) {
++ keys.put("MinimumOSVersion", new NSString(infoPlistSubstitutions.get("MinimumOSVersion")));
++ } else {
++ keys.put("MinimumOSVersion", new NSString(minOSVersion));
++ }
+ if (platformBuildVersion.isPresent()) {
+ keys.put("DTPlatformBuild", new NSString(platformBuildVersion.get()));
+ keys.put("DTSDKBuild", new NSString(platformBuildVersion.get()));
+@@ -1185,9 +1189,10 @@ public class AppleBundle extends AbstractBuildRuleWithDeclaredAndExtraDeps
+
+ // .framework bundles will be code-signed when they're copied into the containing bundle.
+ private boolean needCodeSign() {
+- return binary.isPresent()
++ return false;
++ /*return binary.isPresent()
+ && ApplePlatform.needsCodeSign(platform.getName())
+- && !extension.equals(FRAMEWORK_EXTENSION);
++ && !extension.equals(FRAMEWORK_EXTENSION);*/
+ }
+
+ @Override
+diff --git a/src/com/facebook/buck/apple/MultiarchFileInfos.java b/src/com/facebook/buck/apple/MultiarchFileInfos.java
+index c078b2e134..030f9fc289 100644
+--- a/src/com/facebook/buck/apple/MultiarchFileInfos.java
++++ b/src/com/facebook/buck/apple/MultiarchFileInfos.java
+@@ -177,7 +177,12 @@ public class MultiarchFileInfos {
+ cxxBuckConfig.shouldCacheLinks(),
+ BuildTargetPaths.getGenPath(
+ projectFilesystem, buildTarget, multiarchOutputPathFormat));
+- graphBuilder.addToIndex(multiarchFile);
++ Optional existingRule2 = graphBuilder.getRuleOptional(multiarchFile.getBuildTarget());
++ if (existingRule2.isPresent()) {
++ return existingRule2.get();
++ } else {
++ graphBuilder.addToIndex(multiarchFile);
++ }
+ return multiarchFile;
+ } else {
+ return new NoopBuildRule(buildTarget, projectFilesystem);
+diff --git a/src/com/facebook/buck/features/apple/project/ProjectGenerator.java b/src/com/facebook/buck/features/apple/project/ProjectGenerator.java
+index 8db968b982..b10f793d8e 100644
+--- a/src/com/facebook/buck/features/apple/project/ProjectGenerator.java
++++ b/src/com/facebook/buck/features/apple/project/ProjectGenerator.java
+@@ -825,6 +825,7 @@ public class ProjectGenerator {
+ Optional.of(xcodeDescriptions.getXCodeDescriptions()));
+ if (bundleRequiresRemovalOfAllTransitiveFrameworks(targetNode)) {
+ copiedRules = rulesWithoutFrameworkBundles(copiedRules);
++ copiedRules = rulesWithoutDylibs(copiedRules);
+ } else if (bundleRequiresAllTransitiveFrameworks(binaryNode, bundleLoaderNode)) {
+ copiedRules =
+ ImmutableSet.>builder()
+@@ -954,6 +955,22 @@ public class ProjectGenerator {
+ .toImmutableList();
+ }
+
++ private ImmutableList> rulesWithoutDylibs(
++ Iterable> copiedRules) {
++ return RichStream.from(copiedRules)
++ .filter(
++ input ->
++ TargetNodes.castArg(input, AppleLibraryDescriptionArg.class)
++ .map(argTargetNode -> {
++ if (argTargetNode.getBuildTarget().getFlavors().contains(CxxDescriptionEnhancer.SHARED_FLAVOR)) {
++ return false;
++ }
++ return true;
++ })
++ .orElse(true))
++ .toImmutableList();
++ }
++
+ private ImmutableList> rulesWithoutBundleLoader(
+ Iterable> copiedRules, TargetNode> bundleLoader) {
+ return RichStream.from(copiedRules).filter(x -> !bundleLoader.equals(x)).toImmutableList();
+@@ -2316,8 +2333,9 @@ public class ProjectGenerator {
+ .transform(
+ bundleExtension -> {
+ switch (bundleExtension) {
+- case APP:
+ case APPEX:
++ return false;
++ case APP:
+ case PLUGIN:
+ case BUNDLE:
+ case XCTEST:
+@@ -2515,7 +2533,7 @@ public class ProjectGenerator {
+
+ librarySearchPaths.add("$DT_TOOLCHAIN_DIR/usr/lib/swift/$PLATFORM_NAME");
+ if (options.shouldLinkSystemSwift()) {
+- librarySearchPaths.add("$DT_TOOLCHAIN_DIR/usr/lib/swift-5.0/$PLATFORM_NAME");
++ //librarySearchPaths.add("$DT_TOOLCHAIN_DIR/usr/lib/swift-5.0/$PLATFORM_NAME");
+ }
+ }
+
+@@ -3444,7 +3462,7 @@ public class ProjectGenerator {
+
+ PBXFileReference fileReference = getLibraryFileReference(targetNode);
+ PBXBuildFile buildFile = new PBXBuildFile(fileReference);
+- if (fileReference.getExplicitFileType().equals(Optional.of("wrapper.framework"))) {
++ if (fileReference.getExplicitFileType().equals(Optional.of("wrapper.framework")) || fileReference.getExplicitFileType().equals(Optional.of("compiled.mach-o.dylib"))) {
+ UnflavoredBuildTargetView buildTarget =
+ targetNode.getBuildTarget().getUnflavoredBuildTarget();
+ if (frameworkTargets.contains(buildTarget)) {
+@@ -4696,6 +4714,9 @@ public class ProjectGenerator {
+
+ private static boolean bundleRequiresRemovalOfAllTransitiveFrameworks(
+ TargetNode extends HasAppleBundleFields> targetNode) {
++ if (targetNode.getConstructorArg().getXcodeProductType().equals(Optional.of("com.apple.product-type.app-extension"))) {
++ return true;
++ }
+ return isFrameworkBundle(targetNode.getConstructorArg());
+ }
+
diff --git a/buildbox/buck/prepare_buck_source.sh b/buildbox/buck/prepare_buck_source.sh
new file mode 100644
index 0000000000..2430dda76e
--- /dev/null
+++ b/buildbox/buck/prepare_buck_source.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+ls []
+
+if [ ! -f "" ]; then
+ exit 1
+fi
diff --git a/extract_wallet_source.py b/extract_wallet_source.py
index 2c17d1f782..727e04194a 100644
--- a/extract_wallet_source.py
+++ b/extract_wallet_source.py
@@ -22,12 +22,30 @@ def clean_files(base_dir, dirs, files):
if re.match('.*\\.xcodeproj', dir) or re.match('.*\\.xcworkspace', dir):
shutil.rmtree(base_dir + '/' + dir, ignore_errors=True)
+def clean_dep_files(base_dir, dirs, files):
+ for file in files:
+ if re.match('^\\.git$', file) or re.match('^.*/\\.git$', file):
+ os.remove(base_dir + '/' + file)
+ for dir in dirs:
+ if re.match('^\\.git$', dir) or re.match('^.*/\\.git$', dir):
+ shutil.rmtree(base_dir + '/' + dir, ignore_errors=True)
+
if len(sys.argv) != 2:
print('Usage: extract_wallet_source.py destination')
sys.exit(1)
destination = sys.argv[1]
+initial_dirs, initial_files = get_file_list(destination)
+for file in initial_files:
+ if re.match('^\\.git/.*$', file):
+ continue
+ os.remove(destination + '/' + file)
+for dir in initial_dirs:
+ if dir == '.git' or re.match('^\\.git/.*$', dir):
+ continue
+ shutil.rmtree(destination + '/' + dir, ignore_errors=True)
+
deps_data = os.popen('make -f Wallet.makefile --silent wallet_deps').read()
deps = json.loads(deps_data)
@@ -45,6 +63,8 @@ for dep in deps:
for dep_path in paths:
shutil.copytree(dep_path, destination + '/' + dep_path)
+ dep_dirs, dep_files = get_file_list(destination + '/' + dep_path)
+ clean_dep_files(destination + '/' + dep_path, dep_dirs, dep_files)
result_dirs, result_files = get_file_list(destination)
clean_files(destination, result_dirs, result_files)
@@ -53,6 +73,10 @@ with open(destination + '/BUCK', 'w+b') as file:
pass
shutil.copytree('Config', destination + '/' + 'Config')
+shutil.copytree('tools/buck-build', destination + '/' + 'tools/buck-build')
+
+shutil.copy('Wallet/README.md', destination + '/' + 'README.md')
+os.remove(destination + '/Wallet/' + 'README.md')
copy_files = [
'.buckconfig',
diff --git a/submodules/AppLock/Sources/AppLock.swift b/submodules/AppLock/Sources/AppLock.swift
index 17ead4e47e..c8cdc58649 100644
--- a/submodules/AppLock/Sources/AppLock.swift
+++ b/submodules/AppLock/Sources/AppLock.swift
@@ -17,12 +17,12 @@ private func isLocked(passcodeSettings: PresentationPasscodeSettings, state: Loc
} else if let autolockTimeout = passcodeSettings.autolockTimeout {
var bootTimestamp: Int32 = 0
let uptime = getDeviceUptimeSeconds(&bootTimestamp)
- let timestamp = MonotonicTimestamp(bootTimestap: bootTimestamp, uptime: uptime)
+ let timestamp = MonotonicTimestamp(bootTimestamp: bootTimestamp, uptime: uptime)
let applicationActivityTimestamp = state.applicationActivityTimestamp
if let applicationActivityTimestamp = applicationActivityTimestamp {
- if timestamp.bootTimestap != applicationActivityTimestamp.bootTimestap {
+ if timestamp.bootTimestamp != applicationActivityTimestamp.bootTimestamp {
return true
}
if timestamp.uptime >= applicationActivityTimestamp.uptime + autolockTimeout {
@@ -249,7 +249,7 @@ public final class AppLockContextImpl: AppLockContext {
let uptime = getDeviceUptimeSeconds(&bootTimestamp)
var state = state
- state.applicationActivityTimestamp = MonotonicTimestamp(bootTimestap: bootTimestamp, uptime: uptime)
+ state.applicationActivityTimestamp = MonotonicTimestamp(bootTimestamp: bootTimestamp, uptime: uptime)
return state
}
}
@@ -276,7 +276,7 @@ public final class AppLockContextImpl: AppLockContext {
return self.currentState.get()
|> map { state in
return state.unlockAttemts.flatMap { unlockAttemts in
- return AccessChallengeAttempts(count: unlockAttemts.count, timestamp: unlockAttemts.wallClockTimestamp)
+ return AccessChallengeAttempts(count: unlockAttemts.count, bootTimestamp: unlockAttemts.timestamp.bootTimestamp, uptime: unlockAttemts.timestamp.uptime)
}
}
}
@@ -299,7 +299,7 @@ public final class AppLockContextImpl: AppLockContext {
var bootTimestamp: Int32 = 0
let uptime = getDeviceUptimeSeconds(&bootTimestamp)
- let timestamp = MonotonicTimestamp(bootTimestap: bootTimestamp, uptime: uptime)
+ let timestamp = MonotonicTimestamp(bootTimestamp: bootTimestamp, uptime: uptime)
state.applicationActivityTimestamp = timestamp
return state
@@ -309,9 +309,15 @@ public final class AppLockContextImpl: AppLockContext {
public func failedUnlockAttempt() {
self.updateLockState { state in
var state = state
- var unlockAttemts = state.unlockAttemts ?? UnlockAttempts(count: 0, wallClockTimestamp: 0)
+ var unlockAttemts = state.unlockAttemts ?? UnlockAttempts(count: 0, timestamp: MonotonicTimestamp(bootTimestamp: 0, uptime: 0))
+
unlockAttemts.count += 1
- unlockAttemts.wallClockTimestamp = Int32(CFAbsoluteTimeGetCurrent())
+
+ var bootTimestamp: Int32 = 0
+ let uptime = getDeviceUptimeSeconds(&bootTimestamp)
+ let timestamp = MonotonicTimestamp(bootTimestamp: bootTimestamp, uptime: uptime)
+
+ unlockAttemts.timestamp = timestamp
state.unlockAttemts = unlockAttemts
return state
}
diff --git a/submodules/AppLockState/Sources/AppLockState.swift b/submodules/AppLockState/Sources/AppLockState.swift
index a044c7901c..c632725ab1 100644
--- a/submodules/AppLockState/Sources/AppLockState.swift
+++ b/submodules/AppLockState/Sources/AppLockState.swift
@@ -2,22 +2,22 @@ import Foundation
import MonotonicTime
public struct MonotonicTimestamp: Codable, Equatable {
- public var bootTimestap: Int32
+ public var bootTimestamp: Int32
public var uptime: Int32
- public init(bootTimestap: Int32, uptime: Int32) {
- self.bootTimestap = bootTimestap
+ public init(bootTimestamp: Int32, uptime: Int32) {
+ self.bootTimestamp = bootTimestamp
self.uptime = uptime
}
}
public struct UnlockAttempts: Codable, Equatable {
public var count: Int32
- public var wallClockTimestamp: Int32
+ public var timestamp: MonotonicTimestamp
- public init(count: Int32, wallClockTimestamp: Int32) {
+ public init(count: Int32, timestamp: MonotonicTimestamp) {
self.count = count
- self.wallClockTimestamp = wallClockTimestamp
+ self.timestamp = timestamp
}
}
@@ -45,10 +45,10 @@ public func isAppLocked(state: LockState) -> Bool {
} else if let autolockTimeout = state.autolockTimeout {
var bootTimestamp: Int32 = 0
let uptime = getDeviceUptimeSeconds(&bootTimestamp)
- let timestamp = MonotonicTimestamp(bootTimestap: bootTimestamp, uptime: uptime)
+ let timestamp = MonotonicTimestamp(bootTimestamp: bootTimestamp, uptime: uptime)
if let applicationActivityTimestamp = state.applicationActivityTimestamp {
- if timestamp.bootTimestap != applicationActivityTimestamp.bootTimestap {
+ if timestamp.bootTimestamp != applicationActivityTimestamp.bootTimestamp {
return true
}
if timestamp.uptime >= applicationActivityTimestamp.uptime + autolockTimeout {
diff --git a/submodules/AsyncDisplayKit/.buckconfig b/submodules/AsyncDisplayKit/.buckconfig
deleted file mode 100644
index 821cb2c82f..0000000000
--- a/submodules/AsyncDisplayKit/.buckconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-[cxx]
- default_platform = iphonesimulator-x86_64
- combined_preprocess_and_compile = true
-
-[apple]
- iphonesimulator_target_sdk_version = 8.0
- iphoneos_target_sdk_version = 8.0
- xctool_default_destination_specifier = platform=iOS Simulator, name=iPhone 6, OS=10.2
-
-[alias]
- lib = //:AsyncDisplayKit
- tests = //:Tests
-
-[httpserver]
- port = 8080
-
-[project]
- ide = xcode
- ignore = .buckd, \
- .hg, \
- .git, \
- buck-out, \
diff --git a/submodules/AsyncDisplayKit/.buckversion b/submodules/AsyncDisplayKit/.buckversion
deleted file mode 100644
index 437aedac09..0000000000
--- a/submodules/AsyncDisplayKit/.buckversion
+++ /dev/null
@@ -1 +0,0 @@
-f399f484bf13b47bcc2bf0f2e092ab5d8de9f6e6
diff --git a/submodules/AsyncDisplayKit/.editorconfig b/submodules/AsyncDisplayKit/.editorconfig
deleted file mode 100644
index 0605feef2a..0000000000
--- a/submodules/AsyncDisplayKit/.editorconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# http://editorconfig.org
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[**.{h,cc,mm,m}]
-indent_style = space
-indent_size = 2
-
-[*.{md,markdown}]
-trim_trailing_whitespace = false
-
-# Makefiles always use tabs for indentation
-[Makefile]
-indent_style = tab
\ No newline at end of file
diff --git a/submodules/AsyncDisplayKit/.github/ISSUE_TEMPLATE.md b/submodules/AsyncDisplayKit/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index c5ab71942b..0000000000
--- a/submodules/AsyncDisplayKit/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,7 +0,0 @@
-// If you're looking for help, please consider joining our slack channel:
-// http://asyncdisplaykit.org/slack (we'll be updating the name to Texture soon)
-
-// The more information you include, the faster we can help you out!
-// Please include: a sample project or screenshots, code snippets
-// Texture version, and/or backtraces for any crashes (> bt all).
-// Please delete these lines before posting. Thanks!
diff --git a/submodules/AsyncDisplayKit/.github_changelog_generator b/submodules/AsyncDisplayKit/.github_changelog_generator
deleted file mode 100644
index 5b1ccea517..0000000000
--- a/submodules/AsyncDisplayKit/.github_changelog_generator
+++ /dev/null
@@ -1,3 +0,0 @@
-issues=false
-since-tag=2.8
-future-release=2.9
diff --git a/submodules/AsyncDisplayKit/.slather.yml b/submodules/AsyncDisplayKit/.slather.yml
deleted file mode 100644
index ef84e32dea..0000000000
--- a/submodules/AsyncDisplayKit/.slather.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-ci_service: travis_ci
-coverage_service: coveralls
-xcodeproj: AsyncDisplayKit.xcodeproj
-source_directory: AsyncDisplayKit
-
diff --git a/submodules/AsyncDisplayKit/.travis.yml b/submodules/AsyncDisplayKit/.travis.yml
deleted file mode 100644
index b493cff43c..0000000000
--- a/submodules/AsyncDisplayKit/.travis.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-language: objective-c
-cache:
- - bundler
- - cocoapods
-osx_image: xcode8.1
-git:
- depth: 10
-before_install:
- - brew update
- - brew outdated xctool || brew upgrade xctool
- - brew outdated carthage || brew upgrade carthage
- - gem install cocoapods -v 1.0.1
- - gem install xcpretty -v 0.2.2
- - gem install xcpretty-travis-formatter
-# - gem install slather
- - xcrun simctl list
-install: echo "<3"
-env:
- - MODE=tests
- - MODE=tests_listkit
- - MODE=examples-pt1
- - MODE=examples-pt2
- - MODE=examples-pt3
- - MODE=life-without-cocoapods
- - MODE=framework
-script: ./build.sh $MODE
-
-#after_success:
-# - slather
-
-# whitelist
-branches:
- only:
- - master
diff --git a/submodules/AsyncDisplayKit/CI/build.sh b/submodules/AsyncDisplayKit/CI/build.sh
deleted file mode 100755
index 058cef0542..0000000000
--- a/submodules/AsyncDisplayKit/CI/build.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-set -eo pipefail
-
-./build.sh all
\ No newline at end of file
diff --git a/submodules/AsyncDisplayKit/CI/exclude-from-build.json b/submodules/AsyncDisplayKit/CI/exclude-from-build.json
deleted file mode 100644
index 999e736a52..0000000000
--- a/submodules/AsyncDisplayKit/CI/exclude-from-build.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- "^plans/",
- "^docs/",
- "^CI/exclude-from-build.json$",
- "^**/*.md$"
-]
diff --git a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.h b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.h
index 397d815edb..b30969e3f1 100644
--- a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.h
+++ b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.h
@@ -71,6 +71,8 @@ NS_ASSUME_NONNULL_BEGIN
//! @abstract The range of text currently selected. If length is zero, the range is the cursor location.
@property NSRange selectedRange;
+@property (readonly) CGRect selectionRect;
+
#pragma mark - Placeholder
/**
@abstract Indicates if the receiver is displaying the placeholder text.
diff --git a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm
index 277af0f9c8..21f94b4493 100644
--- a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm
+++ b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm
@@ -566,6 +566,15 @@
_textKitComponents.textView.selectedRange = selectedRange;
}
+- (CGRect)selectionRect {
+ UITextRange *range = [_textKitComponents.textView selectedTextRange];
+ if (range != nil) {
+ return [_textKitComponents.textView firstRectForRange:range];
+ } else {
+ return [_textKitComponents.textView bounds];
+ }
+}
+
#pragma mark - Placeholder
- (BOOL)isDisplayingPlaceholder
{
diff --git a/submodules/AsyncDisplayKit/Tests/ASAbsoluteLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASAbsoluteLayoutSpecSnapshotTests.mm
deleted file mode 100644
index a1b9b94596..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASAbsoluteLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// ASAbsoluteLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-
-@interface ASAbsoluteLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-@end
-
-@implementation ASAbsoluteLayoutSpecSnapshotTests
-
-- (void)testSizingBehaviour
-{
- [self testWithSizeRange:ASSizeRangeMake(CGSizeMake(150, 200), CGSizeMake(INFINITY, INFINITY))
- identifier:@"underflowChildren"];
- [self testWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(50, 100))
- identifier:@"overflowChildren"];
- // Expect the spec to wrap its content because children sizes are between constrained size
- [self testWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY / 2, INFINITY / 2))
- identifier:@"wrappedChildren"];
-}
-
-- (void)testChildrenMeasuredWithAutoMaxSize
-{
- ASDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor], (CGSize){50, 50});
- firstChild.style.layoutPosition = CGPointMake(0, 0);
-
- ASDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor], (CGSize){100, 100});
- secondChild.style.layoutPosition = CGPointMake(10, 60);
-
- ASSizeRange sizeRange = ASSizeRangeMake(CGSizeMake(10, 10), CGSizeMake(110, 160));
- [self testWithChildren:@[firstChild, secondChild] sizeRange:sizeRange identifier:nil];
-}
-
-- (void)testWithSizeRange:(ASSizeRange)sizeRange identifier:(NSString *)identifier
-{
- ASDisplayNode *firstChild = ASDisplayNodeWithBackgroundColor([UIColor redColor], (CGSize){50, 50});
- firstChild.style.layoutPosition = CGPointMake(0, 0);
-
- ASDisplayNode *secondChild = ASDisplayNodeWithBackgroundColor([UIColor blueColor], (CGSize){100, 100});
- secondChild.style.layoutPosition = CGPointMake(0, 50);
-
- [self testWithChildren:@[firstChild, secondChild] sizeRange:sizeRange identifier:identifier];
-}
-
-- (void)testWithChildren:(NSArray *)children sizeRange:(ASSizeRange)sizeRange identifier:(NSString *)identifier
-{
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor whiteColor]);
-
- NSMutableArray *subnodes = [NSMutableArray arrayWithArray:children];
- [subnodes insertObject:backgroundNode atIndex:0];
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:
- [ASAbsoluteLayoutSpec
- absoluteLayoutSpecWithChildren:children]
- background:backgroundNode];
-
- [self testLayoutSpec:layoutSpec sizeRange:sizeRange subnodes:subnodes identifier:identifier];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASBackgroundLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASBackgroundLayoutSpecSnapshotTests.mm
deleted file mode 100644
index 1a6b4fc7c8..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASBackgroundLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// ASBackgroundLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-
-static const ASSizeRange kSize = {{320, 320}, {320, 320}};
-
-@interface ASBackgroundLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-
-@end
-
-@implementation ASBackgroundLayoutSpecSnapshotTests
-
-- (void)testBackground
-{
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor], {20, 20});
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASCenterLayoutSpec
- centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY
- sizingOptions:{}
- child:foregroundNode]
- background:backgroundNode];
-
- [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier: nil];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderContextTests.mm b/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderContextTests.mm
deleted file mode 100644
index 701174b7dd..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderContextTests.mm
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// ASBasicImageDownloaderContextTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-#import
-
-#import
-
-
-@interface ASBasicImageDownloaderContextTests : XCTestCase
-
-@end
-
-@implementation ASBasicImageDownloaderContextTests
-
-- (NSURL *)randomURL
-{
- // random URL for each test, doesn't matter that this is not really a URL
- return [NSURL URLWithString:[NSUUID UUID].UUIDString];
-}
-
-- (void)testContextCreation
-{
- NSURL *url = [self randomURL];
- ASBasicImageDownloaderContext *c1 = [ASBasicImageDownloaderContext contextForURL:url];
- ASBasicImageDownloaderContext *c2 = [ASBasicImageDownloaderContext contextForURL:url];
- XCTAssert(c1 == c2, @"Context objects are not the same");
-}
-
-- (void)testContextInvalidation
-{
- NSURL *url = [self randomURL];
- ASBasicImageDownloaderContext *context = [ASBasicImageDownloaderContext contextForURL:url];
- [context cancel];
- XCTAssert([context isCancelled], @"Context should be cancelled");
-}
-
-/* This test is currently unreliable. See https://github.com/facebook/AsyncDisplayKit/issues/459
-- (void)testAsyncContextInvalidation
-{
- NSURL *url = [self randomURL];
- ASBasicImageDownloaderContext *context = [ASBasicImageDownloaderContext contextForURL:url];
- XCTestExpectation *expectation = [self expectationWithDescription:@"Context invalidation"];
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [expectation fulfill];
- XCTAssert([context isCancelled], @"Context should be cancelled");
- });
-
- [context cancel];
- [self waitForExpectationsWithTimeout:30.0 handler:nil];
-}
-*/
-
-- (void)testContextSessionCanceled
-{
- NSURL *url = [self randomURL];
- id task = [OCMockObject mockForClass:[NSURLSessionTask class]];
- ASBasicImageDownloaderContext *context = [ASBasicImageDownloaderContext contextForURL:url];
- context.sessionTask = task;
-
- [[task expect] cancel];
-
- [context cancel];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderTests.mm b/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderTests.mm
deleted file mode 100644
index 8268dfcd64..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASBasicImageDownloaderTests.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// ASBasicImageDownloaderTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-
-@interface ASBasicImageDownloaderTests : XCTestCase
-
-@end
-
-@implementation ASBasicImageDownloaderTests
-
-- (void)testAsynchronouslyDownloadTheSameURLTwice
-{
- XCTestExpectation *firstExpectation = [self expectationWithDescription:@"First ASBasicImageDownloader completion handler should be called within 3 seconds"];
- XCTestExpectation *secondExpectation = [self expectationWithDescription:@"Second ASBasicImageDownloader completion handler should be called within 3 seconds"];
-
- ASBasicImageDownloader *downloader = [ASBasicImageDownloader sharedImageDownloader];
- NSURL *URL = [NSURL URLWithString:@"http://wrongPath/wrongResource.png"];
-
- [downloader downloadImageWithURL:URL
- callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
- downloadProgress:nil
- completion:^(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) {
- [firstExpectation fulfill];
- }];
-
- [downloader downloadImageWithURL:URL
- callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
- downloadProgress:nil
- completion:^(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier, id _Nullable userInfo) {
- [secondExpectation fulfill];
- }];
-
- [self waitForExpectationsWithTimeout:30 handler:nil];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASBatchFetchingTests.mm b/submodules/AsyncDisplayKit/Tests/ASBatchFetchingTests.mm
deleted file mode 100644
index 99b67f05c0..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASBatchFetchingTests.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-// ASBatchFetchingTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-
-@interface ASBatchFetchingTests : XCTestCase
-
-@end
-
-@implementation ASBatchFetchingTests
-
-#define PASSING_RECT CGRectMake(0,0,1,1)
-#define PASSING_SIZE CGSizeMake(1,1)
-#define PASSING_POINT CGPointMake(1,1)
-#define VERTICAL_RECT(h) CGRectMake(0,0,1,h)
-#define VERTICAL_SIZE(h) CGSizeMake(0,h)
-#define VERTICAL_OFFSET(y) CGPointMake(0,y)
-#define HORIZONTAL_RECT(w) CGRectMake(0,0,w,1)
-#define HORIZONTAL_SIZE(w) CGSizeMake(w,0)
-#define HORIZONTAL_OFFSET(x) CGPointMake(x,0)
-
-- (void)testBatchNullState {
- ASBatchContext *context = [[ASBatchContext alloc] init];
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, CGRectZero, CGSizeZero, CGPointZero, 0.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == NO, @"Should not fetch in the null state");
-}
-
-- (void)testBatchAlreadyFetching {
- ASBatchContext *context = [[ASBatchContext alloc] init];
- [context beginBatchFetching];
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == NO, @"Should not fetch when context is already fetching");
-}
-
-- (void)testUnsupportedScrollDirections {
- ASBatchContext *context = [[ASBatchContext alloc] init];
- BOOL fetchRight = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil);
- XCTAssert(fetchRight == YES, @"Should fetch for scrolling right");
- BOOL fetchDown = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil);
- XCTAssert(fetchDown == YES, @"Should fetch for scrolling down");
- BOOL fetchUp = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionUp, ASScrollDirectionVerticalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil);
- XCTAssert(fetchUp == NO, @"Should not fetch for scrolling up");
- BOOL fetchLeft = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, PASSING_RECT, PASSING_SIZE, PASSING_POINT, 1.0, YES, CGPointZero, nil);
- XCTAssert(fetchLeft == NO, @"Should not fetch for scrolling left");
-}
-
-- (void)testVerticalScrollToExactLeading {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // scroll to 1-screen top offset, height is 1 screen, so bottom is 1 screen away from end of content
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 1.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling to exactly 1 leading screen away");
-}
-
-- (void)testVerticalScrollToLessThanLeading {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // 3 screens of content, scroll only 1/2 of one screen
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 0.5), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == NO, @"Fetch should not begin when vertically scrolling less than the leading distance away");
-}
-
-- (void)testVerticalScrollingPastContentSize {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // 3 screens of content, top offset to 3-screens, height 1 screen, so its 1 screen past the leading
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 3.0), VERTICAL_OFFSET(screen * 3.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling past the content size");
-}
-
-- (void)testHorizontalScrollToExactLeading {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // scroll to 1-screen left offset, width is 1 screen, so right is 1 screen away from end of content
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionVerticalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 1.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when horizontally scrolling to exactly 1 leading screen away");
-}
-
-- (void)testHorizontalScrollToLessThanLeading {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // 3 screens of content, scroll only 1/2 of one screen
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionLeft, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 0.5), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == NO, @"Fetch should not begin when horizontally scrolling less than the leading distance away");
-}
-
-- (void)testHorizontalScrollingPastContentSize {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // 3 screens of content, left offset to 3-screens, width 1 screen, so its 1 screen past the leading
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 3.0), HORIZONTAL_OFFSET(screen * 3.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when vertically scrolling past the content size");
-}
-
-- (void)testVerticalScrollingSmallContentSize {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // when the content size is < screen size, the target offset will always be 0
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionDown, ASScrollDirectionVerticalDirections, VERTICAL_RECT(screen), VERTICAL_SIZE(screen * 0.5), VERTICAL_OFFSET(0.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree");
-}
-
-- (void)testHorizontalScrollingSmallContentSize {
- CGFloat screen = 1.0;
- ASBatchContext *context = [[ASBatchContext alloc] init];
- // when the content size is < screen size, the target offset will always be 0
- BOOL shouldFetch = ASDisplayShouldFetchBatchForContext(context, ASScrollDirectionRight, ASScrollDirectionHorizontalDirections, HORIZONTAL_RECT(screen), HORIZONTAL_SIZE(screen * 0.5), HORIZONTAL_OFFSET(0.0), 1.0, YES, CGPointZero, nil);
- XCTAssert(shouldFetch == YES, @"Fetch should begin when the target is 0 and the content size is smaller than the scree");
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASBridgedPropertiesTests.mm b/submodules/AsyncDisplayKit/Tests/ASBridgedPropertiesTests.mm
deleted file mode 100644
index 8e4a202eb8..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASBridgedPropertiesTests.mm
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// ASBridgedPropertiesTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-
-@interface ASPendingStateController (Testing)
-- (BOOL)test_isFlushScheduled;
-@end
-
-@interface ASBridgedPropertiesTestView : UIView
-@property (nonatomic, readonly) BOOL receivedSetNeedsLayout;
-@end
-
-@implementation ASBridgedPropertiesTestView
-
-- (void)setNeedsLayout
-{
- _receivedSetNeedsLayout = YES;
- [super setNeedsLayout];
-}
-
-@end
-
-@interface ASBridgedPropertiesTestNode : ASDisplayNode
-@property (nullable, nonatomic, copy) dispatch_block_t onDealloc;
-@end
-
-@implementation ASBridgedPropertiesTestNode
-
-- (void)dealloc {
- _onDealloc();
-}
-
-@end
-
-@interface ASBridgedPropertiesTests : XCTestCase
-@end
-
-/// Dispatches the given block synchronously onto a different thread.
-/// This is useful for testing non-main-thread behavior because `dispatch_sync`
-/// will often use the current thread.
-static inline void ASDispatchSyncOnOtherThread(dispatch_block_t block) {
- dispatch_group_t group = dispatch_group_create();
- dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_enter(group);
- dispatch_async(q, ^{
- ASDisplayNodeCAssertNotMainThread();
- block();
- dispatch_group_leave(group);
- });
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-}
-
-@implementation ASBridgedPropertiesTests
-
-- (void)testTheresASharedInstance
-{
- XCTAssertNotNil([ASPendingStateController sharedInstance]);
-}
-
-/// FIXME: This test is unreliable for an as-yet unknown reason
-/// but that being intermittent, and this test being so strict, it's
-/// reasonable to assume for now the failures don't reflect a framework bug.
-/// See https://github.com/facebook/AsyncDisplayKit/pull/1048
-- (void)DISABLED_testThatDirtyNodesAreNotRetained
-{
- ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
- __block BOOL didDealloc = NO;
- @autoreleasepool {
- __attribute__((objc_precise_lifetime)) ASBridgedPropertiesTestNode *node = [ASBridgedPropertiesTestNode new];
- node.onDealloc = ^{
- didDealloc = YES;
- };
- [node view];
- XCTAssertEqual(node.alpha, 1);
- ASDispatchSyncOnOtherThread(^{
- node.alpha = 0;
- });
- XCTAssertEqual(node.alpha, 1);
- XCTAssert(ctrl.test_isFlushScheduled);
- }
- XCTAssertTrue(didDealloc);
-}
-
-- (void)testThatSettingABridgedViewPropertyInBackgroundGetsFlushedOnNextRunLoop
-{
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- XCTAssertEqual(node.alpha, 1);
- ASDispatchSyncOnOtherThread(^{
- node.alpha = 0;
- });
- XCTAssertEqual(node.alpha, 1);
- [self waitForMainDispatchQueueToFlush];
- XCTAssertEqual(node.alpha, 0);
-}
-
-- (void)testThatSettingABridgedLayerPropertyInBackgroundGetsFlushedOnNextRunLoop
-{
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- XCTAssertEqual(node.shadowOpacity, 0);
- ASDispatchSyncOnOtherThread(^{
- node.shadowOpacity = 1;
- });
- XCTAssertEqual(node.shadowOpacity, 0);
- [self waitForMainDispatchQueueToFlush];
- XCTAssertEqual(node.shadowOpacity, 1);
-}
-
-- (void)testThatReadingABridgedViewPropertyInBackgroundThrowsAnException
-{
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- ASDispatchSyncOnOtherThread(^{
- XCTAssertThrows(node.alpha);
- });
-}
-
-- (void)testThatReadingABridgedLayerPropertyInBackgroundThrowsAnException
-{
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- ASDispatchSyncOnOtherThread(^{
- XCTAssertThrows(node.contentsScale);
- });
-}
-
-- (void)testThatManuallyFlushingTheSyncControllerImmediatelyAppliesChanges
-{
- ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- XCTAssertEqual(node.alpha, 1);
- ASDispatchSyncOnOtherThread(^{
- node.alpha = 0;
- });
- XCTAssertEqual(node.alpha, 1);
- [ctrl flush];
- XCTAssertEqual(node.alpha, 0);
- XCTAssertFalse(ctrl.test_isFlushScheduled);
-}
-
-- (void)testThatFlushingTheControllerInBackgroundThrows
-{
- ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
- ASDisplayNode *node = [ASDisplayNode new];
- [node view];
- XCTAssertEqual(node.alpha, 1);
- ASDispatchSyncOnOtherThread(^{
- node.alpha = 0;
- XCTAssertThrows([ctrl flush]);
- });
-}
-
-- (void)testThatSettingABridgedPropertyOnMainThreadPassesDirectlyToView
-{
- ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
- ASDisplayNode *node = [ASDisplayNode new];
- XCTAssertFalse(ASDisplayNodeGetPendingState(node).hasChanges);
- [node view];
- XCTAssertEqual(node.alpha, 1);
- node.alpha = 0;
- XCTAssertEqual(node.view.alpha, 0);
- XCTAssertEqual(node.alpha, 0);
- XCTAssertFalse(ASDisplayNodeGetPendingState(node).hasChanges);
- XCTAssertFalse(ctrl.test_isFlushScheduled);
-}
-
-- (void)testThatCallingSetNeedsLayoutFromBackgroundCausesItToHappenLater
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewClass:ASBridgedPropertiesTestView.class];
- ASBridgedPropertiesTestView *view = (ASBridgedPropertiesTestView *)node.view;
- XCTAssertFalse(view.receivedSetNeedsLayout);
- ASDispatchSyncOnOtherThread(^{
- XCTAssertNoThrow([node setNeedsLayout]);
- });
- XCTAssertFalse(view.receivedSetNeedsLayout);
- [self waitForMainDispatchQueueToFlush];
- XCTAssertTrue(view.receivedSetNeedsLayout);
-}
-
-- (void)testThatCallingSetNeedsLayoutOnACellNodeFromBackgroundIsSafe
-{
- ASCellNode *node = [ASCellNode new];
- [node view];
- ASDispatchSyncOnOtherThread(^{
- XCTAssertNoThrow([node setNeedsLayout]);
- });
-}
-
-- (void)testThatCallingSetNeedsDisplayFromBackgroundCausesItToHappenLater
-{
- ASDisplayNode *node = [ASDisplayNode new];
- [node.layer displayIfNeeded];
- XCTAssertFalse(node.layer.needsDisplay);
- ASDispatchSyncOnOtherThread(^{
- XCTAssertNoThrow([node setNeedsDisplay]);
- });
- XCTAssertFalse(node.layer.needsDisplay);
- [self waitForMainDispatchQueueToFlush];
- XCTAssertTrue(node.layer.needsDisplay);
-}
-
-/// [XCTExpectation expectationWithPredicate:] should handle this
-/// but under Xcode 7.2.1 its polling interval is 1 second
-/// which makes the tests really slow and I'm impatient.
-- (void)waitForMainDispatchQueueToFlush
-{
- __block BOOL done = NO;
- dispatch_async(dispatch_get_main_queue(), ^{
- done = YES;
- });
- while (!done) {
- [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASButtonNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASButtonNodeTests.mm
deleted file mode 100644
index 244edd1f0e..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASButtonNodeTests.mm
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// ASButtonNodeTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-
-@interface ASButtonNodeTests : XCTestCase
-@end
-
-@implementation ASButtonNodeTests
-
-- (void)testAccessibility
-{
- // Setup a button with some title.
- ASButtonNode *buttonNode = nil;
- buttonNode = [[ASButtonNode alloc] init];
- NSString *title = @"foo";
- [buttonNode setTitle:title withFont:nil withColor:nil forState:UIControlStateNormal];
-
- // Verify accessibility properties.
- XCTAssertTrue(buttonNode.accessibilityTraits == UIAccessibilityTraitButton,
- @"Should have button accessibility trait, instead has %llu",
- buttonNode.accessibilityTraits);
- XCTAssertTrue(buttonNode.defaultAccessibilityTraits == UIAccessibilityTraitButton,
- @"Default accessibility traits should return button accessibility trait, instead "
- @"returns %llu",
- buttonNode.defaultAccessibilityTraits);
- XCTAssertTrue([buttonNode.accessibilityLabel isEqualToString:title],
- @"Accessibility label is incorrectly set to \n%@\n when it should be \n%@\n",
- buttonNode.accessibilityLabel, title);
- XCTAssertTrue([buttonNode.defaultAccessibilityLabel isEqualToString:title],
- @"Default accessibility label incorrectly returns \n%@\n when it should be \n%@\n",
- buttonNode.defaultAccessibilityLabel, title);
-
- // Disable the button and verify that accessibility traits has been updated correctly.
- buttonNode.enabled = NO;
- UIAccessibilityTraits disabledButtonTrait = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled;
- XCTAssertTrue(buttonNode.accessibilityTraits == disabledButtonTrait,
- @"Should have disabled button accessibility trait, instead has %llu",
- buttonNode.accessibilityTraits);
- XCTAssertTrue(buttonNode.defaultAccessibilityTraits == disabledButtonTrait,
- @"Default accessibility traits should return disabled button accessibility trait, "
- @"instead returns %llu",
- buttonNode.defaultAccessibilityTraits);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCALayerTests.mm b/submodules/AsyncDisplayKit/Tests/ASCALayerTests.mm
deleted file mode 100644
index 2b30da28fc..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCALayerTests.mm
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-// ASCALayerTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-
-/**
- * Tests that confirm what we know about Core Animation behavior.
- *
- * These tests are not run during the normal test action. You can run them yourself
- * to investigate and confirm CA behavior.
- */
-@interface ASCALayerTests : XCTestCase
-
-@end
-
-#define DeclareLayerAndSublayer() \
- CALayer *realSublayer = [CALayer layer]; \
- id layer = [OCMockObject partialMockForObject:[CALayer layer]]; \
- id sublayer = [OCMockObject partialMockForObject:realSublayer]; \
- [layer addSublayer:realSublayer];
-
-@implementation ASCALayerTests
-
-- (void)testThatLayerBeginsWithCleanLayout
-{
- XCTAssertFalse([CALayer layer].needsLayout);
-}
-
-- (void)testThatAddingSublayersDirtysLayout
-{
- CALayer *layer = [CALayer layer];
- [layer addSublayer:[CALayer layer]];
- XCTAssertTrue([layer needsLayout]);
-}
-
-- (void)testThatRemovingSublayersDirtysLayout
-{
- DeclareLayerAndSublayer();
- [layer layoutIfNeeded];
- XCTAssertFalse([layer needsLayout]);
- [sublayer removeFromSuperlayer];
- XCTAssertTrue([layer needsLayout]);
-}
-
-- (void)testDirtySublayerLayoutDoesntDirtySuperlayer
-{
- DeclareLayerAndSublayer();
- [layer layoutIfNeeded];
-
- // Dirtying sublayer doesn't dirty superlayer.
- [sublayer setNeedsLayout];
- XCTAssertTrue([sublayer needsLayout]);
- XCTAssertFalse([layer needsLayout]);
- [[[sublayer expect] andForwardToRealObject] layoutSublayers];
- // NOTE: We specifically don't expect layer to get -layoutSublayers
- [sublayer layoutIfNeeded];
- [sublayer verify];
- [layer verify];
-}
-
-- (void)testDirtySuperlayerLayoutDoesntDirtySublayerLayout
-{
- DeclareLayerAndSublayer();
- [layer layoutIfNeeded];
-
- // Dirtying superlayer doesn't dirty sublayer.
- [layer setNeedsLayout];
- XCTAssertTrue([layer needsLayout]);
- XCTAssertFalse([sublayer needsLayout]);
- [[[layer expect] andForwardToRealObject] layoutSublayers];
- // NOTE: We specifically don't expect sublayer to get -layoutSublayers
- [layer layoutIfNeeded];
- [sublayer verify];
- [layer verify];
-}
-
-- (void)testDirtyHierarchyIsLaidOutTopDown
-{
- DeclareLayerAndSublayer();
- [sublayer setNeedsLayout];
-
- XCTAssertTrue([layer needsLayout]);
- XCTAssertTrue([sublayer needsLayout]);
-
- __block BOOL superlayerLaidOut = NO;
- [[[[layer expect] andDo:^(NSInvocation *i) {
- superlayerLaidOut = YES;
- }] andForwardToRealObject] layoutSublayers];
-
- [[[[sublayer expect] andDo:^(NSInvocation *i) {
- XCTAssertTrue(superlayerLaidOut);
- }] andForwardToRealObject] layoutSublayers];
-
- [layer layoutIfNeeded];
- [sublayer verify];
- [layer verify];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCenterLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASCenterLayoutSpecSnapshotTests.mm
deleted file mode 100644
index d0352bb446..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCenterLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// ASCenterLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-#import
-
-static const ASSizeRange kSize = {{100, 120}, {320, 160}};
-
-@interface ASCenterLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-@end
-
-@implementation ASCenterLayoutSpecSnapshotTests
-
-- (void)testWithOptions
-{
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:{}];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:{}];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringX sizingOptions:{}];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringY sizingOptions:{}];
-}
-
-- (void)testWithSizingOptions
-{
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
- sizingOptions:ASCenterLayoutSpecSizingOptionDefault];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
- sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
- sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY];
- [self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
- sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY];
-}
-
-- (void)testWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)options
- sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions
-{
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(70, 100));
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASCenterLayoutSpec
- centerLayoutSpecWithCenteringOptions:options
- sizingOptions:sizingOptions
- child:foregroundNode]
- background:backgroundNode];
-
- [self testLayoutSpec:layoutSpec
- sizeRange:kSize
- subnodes:@[backgroundNode, foregroundNode]
- identifier:suffixForCenteringOptions(options, sizingOptions)];
-}
-
-static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions centeringOptions,
- ASCenterLayoutSpecSizingOptions sizingOptinos)
-{
- NSMutableString *suffix = [NSMutableString string];
-
- if ((centeringOptions & ASCenterLayoutSpecCenteringX) != 0) {
- [suffix appendString:@"CenteringX"];
- }
-
- if ((centeringOptions & ASCenterLayoutSpecCenteringY) != 0) {
- [suffix appendString:@"CenteringY"];
- }
-
- if ((sizingOptinos & ASCenterLayoutSpecSizingOptionMinimumX) != 0) {
- [suffix appendString:@"SizingMinimumX"];
- }
-
- if ((sizingOptinos & ASCenterLayoutSpecSizingOptionMinimumY) != 0) {
- [suffix appendString:@"SizingMinimumY"];
- }
-
- return suffix;
-}
-
-- (void)testMinimumSizeRangeIsGivenToChildWhenNotCentering
-{
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor], CGSizeMake(10, 10));
- foregroundNode.style.flexGrow = 1;
-
- ASCenterLayoutSpec *layoutSpec =
- [ASCenterLayoutSpec
- centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone
- sizingOptions:{}
- child:
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASStackLayoutSpec
- stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
- spacing:0
- justifyContent:ASStackLayoutJustifyContentStart
- alignItems:ASStackLayoutAlignItemsStart
- children:@[foregroundNode]]
- background:backgroundNode]];
-
- [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCollectionModernDataSourceTests.mm b/submodules/AsyncDisplayKit/Tests/ASCollectionModernDataSourceTests.mm
deleted file mode 100644
index 5d0a77899a..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCollectionModernDataSourceTests.mm
+++ /dev/null
@@ -1,363 +0,0 @@
-//
-// ASCollectionModernDataSourceTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-#import "OCMockObject+ASAdditions.h"
-#import "ASTestCase.h"
-
-@interface ASCollectionModernDataSourceTests : ASTestCase
-@end
-
-@interface ASTestCellNode : ASCellNode
-@end
-
-@interface ASTestSection : NSObject
-@property (nonatomic, readonly) NSMutableArray *nodeModels;
-@end
-
-@implementation ASCollectionModernDataSourceTests {
-@private
- id mockDataSource;
- UIWindow *window;
- UIViewController *viewController;
- ASCollectionNode *collectionNode;
- NSMutableArray *sections;
-}
-
-- (void)setUp {
- [super setUp];
- // Default is 2 sections: 2 items in first, 1 item in second.
- sections = [NSMutableArray array];
- [sections addObject:[ASTestSection new]];
- [sections[0].nodeModels addObject:[NSObject new]];
- [sections[0].nodeModels addObject:[NSObject new]];
- [sections addObject:[ASTestSection new]];
- [sections[1].nodeModels addObject:[NSObject new]];
- window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- viewController = [[UIViewController alloc] init];
-
- window.rootViewController = viewController;
- [window makeKeyAndVisible];
- collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
- collectionNode.frame = viewController.view.bounds;
- collectionNode.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [viewController.view addSubnode:collectionNode];
-
- mockDataSource = OCMStrictProtocolMock(@protocol(ASCollectionDataSource));
- [mockDataSource addImplementedOptionalProtocolMethods:
- @selector(numberOfSectionsInCollectionNode:),
- @selector(collectionNode:numberOfItemsInSection:),
- @selector(collectionNode:nodeBlockForItemAtIndexPath:),
- @selector(collectionNode:nodeModelForItemAtIndexPath:),
- @selector(collectionNode:contextForSection:),
- nil];
- [mockDataSource setExpectationOrderMatters:YES];
-
- // NOTE: Adding optionally-implemented methods after this point won't work due to ASCollectionNode selector caching.
- collectionNode.dataSource = mockDataSource;
-}
-
-- (void)tearDown
-{
- [collectionNode waitUntilAllUpdatesAreProcessed];
- [super tearDown];
-}
-
-#pragma mark - Test Methods
-
-- (void)testInitialDataLoading
-{
- [self loadInitialData];
-}
-
-- (void)testReloadingAnItem
-{
- [self loadInitialData];
-
- // Reload at (0, 0)
- NSIndexPath *reloadedPath = [NSIndexPath indexPathForItem:0 inSection:0];
-
- [self performUpdateReloadingSections:nil
- reloadingItems:@{ reloadedPath: [NSObject new] }
- reloadMappings:@{ reloadedPath: reloadedPath }
- insertingItems:nil
- deletingItems:nil
- skippedReloadIndexPaths:nil];
-}
-
-- (void)testInsertingAnItem
-{
- [self loadInitialData];
-
- // Insert at (1, 0)
- NSIndexPath *insertedPath = [NSIndexPath indexPathForItem:0 inSection:1];
-
- [self performUpdateReloadingSections:nil
- reloadingItems:nil
- reloadMappings:nil
- insertingItems:@{ insertedPath: [NSObject new] }
- deletingItems:nil
- skippedReloadIndexPaths:nil];
-}
-
-- (void)testReloadingAnItemWithACompatibleNodeModel
-{
- [self loadInitialData];
-
- // Reload and delete together, for good measure.
- NSIndexPath *reloadedPath = [NSIndexPath indexPathForItem:1 inSection:0];
- NSIndexPath *deletedPath = [NSIndexPath indexPathForItem:0 inSection:0];
-
- id nodeModel = [NSObject new];
-
- // Cell node should get -canUpdateToNodeModel:
- id mockCellNode = [collectionNode nodeForItemAtIndexPath:reloadedPath];
- OCMExpect([mockCellNode canUpdateToNodeModel:nodeModel])
- .andReturn(YES);
-
- [self performUpdateReloadingSections:nil
- reloadingItems:@{ reloadedPath: nodeModel }
- reloadMappings:@{ reloadedPath: [NSIndexPath indexPathForItem:0 inSection:0] }
- insertingItems:nil
- deletingItems:@[ deletedPath ]
- skippedReloadIndexPaths:@[ reloadedPath ]];
-}
-
-- (void)testReloadingASection
-{
- [self loadInitialData];
-
- [self performUpdateReloadingSections:@{ @0: [ASTestSection new] }
- reloadingItems:nil
- reloadMappings:nil
- insertingItems:nil
- deletingItems:nil
- skippedReloadIndexPaths:nil];
-}
-
-#pragma mark - Helpers
-
-- (void)loadInitialData
-{
- // Count methods are called twice in a row for first data load.
- // Since -reloadData is routed through our batch update system,
- // the batch update latches the "old data source counts" if needed at -beginUpdates time
- // and then verifies them against the "new data source counts" after the updates.
- // This isn't ideal, but the cost is very small and the system works well.
- for (int i = 0; i < 2; i++) {
- // It reads all the counts
- [self expectDataSourceCountMethods];
- }
-
- // It reads each section object.
- for (NSInteger section = 0; section < sections.count; section++) {
- [self expectContextMethodForSection:section];
- }
-
- // It reads the contents for each item.
- for (NSInteger section = 0; section < sections.count; section++) {
- NSArray *nodeModels = sections[section].nodeModels;
-
- // For each item:
- for (NSInteger i = 0; i < nodeModels.count; i++) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:section];
- [self expectNodeModelMethodForItemAtIndexPath:indexPath nodeModel:nodeModels[i]];
- [self expectNodeBlockMethodForItemAtIndexPath:indexPath];
- }
- }
-
- [window layoutIfNeeded];
-
- // Assert item counts & content:
- [self assertCollectionNodeContent];
-}
-
-/**
- * Adds expectations for the sequence:
- *
- * numberOfSectionsInCollectionNode:
- * for section in countsArray
- * numberOfItemsInSection:
- */
-- (void)expectDataSourceCountMethods
-{
- // -numberOfSectionsInCollectionNode
- OCMExpect([mockDataSource numberOfSectionsInCollectionNode:collectionNode])
- .andReturn(sections.count);
-
- // For each section:
- // Note: Skip fast enumeration for readability.
- for (NSInteger section = 0; section < sections.count; section++) {
- OCMExpect([mockDataSource collectionNode:collectionNode numberOfItemsInSection:section])
- .andReturn(sections[section].nodeModels.count);
- }
-}
-
-- (void)expectNodeModelMethodForItemAtIndexPath:(NSIndexPath *)indexPath nodeModel:(id)nodeModel
-{
- OCMExpect([mockDataSource collectionNode:collectionNode nodeModelForItemAtIndexPath:indexPath])
- .andReturn(nodeModel);
-}
-
-- (void)expectContextMethodForSection:(NSInteger)section
-{
- OCMExpect([mockDataSource collectionNode:collectionNode contextForSection:section])
- .andReturn(sections[section]);
-}
-
-- (void)expectNodeBlockMethodForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- OCMExpect([mockDataSource collectionNode:collectionNode nodeBlockForItemAtIndexPath:indexPath])
- .andReturn((ASCellNodeBlock)^{
- ASCellNode *node = [ASTestCellNode new];
- // Generating multiple partial mocks of the same class is not thread-safe.
- id mockNode;
- @synchronized (NSNull.null) {
- mockNode = OCMPartialMock(node);
- }
- [mockNode setExpectationOrderMatters:YES];
- return mockNode;
- });
-}
-
-/// Asserts that counts match and all view-models are up-to-date between us and collectionNode.
-- (void)assertCollectionNodeContent
-{
- // Assert section count
- XCTAssertEqual(collectionNode.numberOfSections, sections.count);
-
- for (NSInteger section = 0; section < sections.count; section++) {
- ASTestSection *sectionObject = sections[section];
- NSArray *nodeModels = sectionObject.nodeModels;
-
- // Assert section object
- XCTAssertEqualObjects([collectionNode contextForSection:section], sectionObject);
-
- // Assert item count
- XCTAssertEqual([collectionNode numberOfItemsInSection:section], nodeModels.count);
- for (NSInteger item = 0; item < nodeModels.count; item++) {
- // Assert node model
- // Could use pointer equality but the error message is less readable.
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
- id nodeModel = nodeModels[indexPath.item];
- XCTAssertEqualObjects(nodeModel, [collectionNode nodeModelForItemAtIndexPath:indexPath]);
- ASCellNode *node = [collectionNode nodeForItemAtIndexPath:indexPath];
- XCTAssertEqualObjects(node.nodeModel, nodeModel);
- }
- }
-}
-
-/**
- * Updates the collection node, with expectations and assertions about the call-order and the correctness of the
- * new data. You should update the data source _before_ calling this method.
- *
- * skippedReloadIndexPaths are the old index paths for nodes that should use -canUpdateToNodeModel: instead of being refetched.
- */
-- (void)performUpdateReloadingSections:(NSDictionary *)reloadedSections
- reloadingItems:(NSDictionary *)reloadedItems
- reloadMappings:(NSDictionary *)reloadMappings
- insertingItems:(NSDictionary *)insertedItems
- deletingItems:(NSArray *)deletedItems
- skippedReloadIndexPaths:(NSArray *)skippedReloadIndexPaths
-{
- [collectionNode performBatchUpdates:^{
- // First update our data source.
- [reloadedItems enumerateKeysAndObjectsUsingBlock:^(NSIndexPath * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
- sections[key.section].nodeModels[key.item] = obj;
- }];
- [reloadedSections enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
- sections[key.integerValue] = obj;
- }];
-
- // Deletion paths, sorted descending
- for (NSIndexPath *indexPath in [deletedItems sortedArrayUsingSelector:@selector(compare:)].reverseObjectEnumerator) {
- [sections[indexPath.section].nodeModels removeObjectAtIndex:indexPath.item];
- }
-
- // Insertion paths, sorted ascending.
- NSArray *insertionsSortedAcending = [insertedItems.allKeys sortedArrayUsingSelector:@selector(compare:)];
- for (NSIndexPath *indexPath in insertionsSortedAcending) {
- [sections[indexPath.section].nodeModels insertObject:insertedItems[indexPath] atIndex:indexPath.item];
- }
-
- // Then update the collection node.
- NSMutableIndexSet *reloadedSectionIndexes = [NSMutableIndexSet indexSet];
- for (NSNumber *i in reloadedSections) {
- [reloadedSectionIndexes addIndex:i.integerValue];
- }
- [collectionNode reloadSections:reloadedSectionIndexes];
- [collectionNode reloadItemsAtIndexPaths:reloadedItems.allKeys];
- [collectionNode deleteItemsAtIndexPaths:deletedItems];
- [collectionNode insertItemsAtIndexPaths:insertedItems.allKeys];
-
- // Before the commit, lay out our expectations.
-
- // Expect it to load the new counts.
- [self expectDataSourceCountMethods];
-
- // Combine reloads + inserts and expect them to load content for all of them, in ascending order.
- NSMutableDictionary *insertsPlusReloads = [[NSMutableDictionary alloc] initWithDictionary:insertedItems];
-
- // Go through reloaded sections and add all their items into `insertsPlusReloads`
- [reloadedSectionIndexes enumerateIndexesUsingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
- [self expectContextMethodForSection:section];
- NSArray *nodeModels = sections[section].nodeModels;
- for (NSInteger i = 0; i < nodeModels.count; i++) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:section];
- insertsPlusReloads[indexPath] = nodeModels[i];
- }
- }];
-
- [reloadedItems enumerateKeysAndObjectsUsingBlock:^(NSIndexPath * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
- insertsPlusReloads[reloadMappings[key]] = obj;
- }];
-
- for (NSIndexPath *indexPath in [insertsPlusReloads.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
- [self expectNodeModelMethodForItemAtIndexPath:indexPath nodeModel:insertsPlusReloads[indexPath]];
- NSIndexPath *oldIndexPath = [reloadMappings allKeysForObject:indexPath].firstObject;
- BOOL isSkippedReload = oldIndexPath && [skippedReloadIndexPaths containsObject:oldIndexPath];
- if (!isSkippedReload) {
- [self expectNodeBlockMethodForItemAtIndexPath:indexPath];
- }
- }
- } completion:nil];
-
- // Assert that the counts and node models are all correct now.
- [self assertCollectionNodeContent];
-}
-
-@end
-
-#pragma mark - Other Objects
-
-@implementation ASTestCellNode
-
-- (BOOL)canUpdateToNodeModel:(id)nodeModel
-{
- // Our tests default to NO for migrating node models. We use OCMExpect to return YES when we specifically want to.
- return NO;
-}
-
-@end
-
-@implementation ASTestSection
-@synthesize collectionView;
-@synthesize sectionName;
-
-- (instancetype)init
-{
- if (self = [super init]) {
- _nodeModels = [NSMutableArray array];
- }
- return self;
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCollectionViewFlowLayoutInspectorTests.mm b/submodules/AsyncDisplayKit/Tests/ASCollectionViewFlowLayoutInspectorTests.mm
deleted file mode 100644
index 555fe21134..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCollectionViewFlowLayoutInspectorTests.mm
+++ /dev/null
@@ -1,428 +0,0 @@
-//
-// ASCollectionViewFlowLayoutInspectorTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import "ASXCTExtensions.h"
-
-#import
-#import
-#import
-#import
-#import
-
-@interface ASCollectionView (Private)
-
-- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
-
-@end
-
-/**
- * Test Data Source
- */
-@interface InspectorTestDataSource : NSObject
-@end
-
-@implementation InspectorTestDataSource
-
-- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- return [[ASCellNode alloc] init];
-}
-
-- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- return ^{ return [[ASCellNode alloc] init]; };
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-{
- return 0;
-}
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
-{
- return 2;
-}
-
-@end
-
-@protocol InspectorTestDataSourceDelegateProtocol
-
-@end
-
-@interface InspectorTestDataSourceDelegateWithoutNodeConstrainedSize : NSObject
-@end
-
-@implementation InspectorTestDataSourceDelegateWithoutNodeConstrainedSize
-
-- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- return ^{ return [[ASCellNode alloc] init]; };
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-{
- return 0;
-}
-
-@end
-
-@interface ASCollectionViewFlowLayoutInspectorTests : XCTestCase
-
-@end
-
-/**
- * Test Delegate for Header Reference Size Implementation
- */
-@interface HeaderReferenceSizeTestDelegate : NSObject
-
-@end
-
-@implementation HeaderReferenceSizeTestDelegate
-
-- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
-{
- return CGSizeMake(125.0, 125.0);
-}
-
-@end
-
-/**
- * Test Delegate for Footer Reference Size Implementation
- */
-@interface FooterReferenceSizeTestDelegate : NSObject
-
-@end
-
-@implementation FooterReferenceSizeTestDelegate
-
-- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
-{
- return CGSizeMake(125.0, 125.0);
-}
-
-@end
-
-@implementation ASCollectionViewFlowLayoutInspectorTests
-
-- (void)setUp {
- [super setUp];
- // Put setup code here. This method is called before the invocation of each test method in the class.
-}
-
-- (void)tearDown {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- [super tearDown];
-}
-
-#pragma mark - #collectionView:constrainedSizeForSupplementaryNodeOfKind:atIndexPath:
-
-// Vertical
-
-// Delegate implementation
-
-- (void)testThatItReturnsAVerticalConstrainedSizeFromTheHeaderDelegateImplementation
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionVertical;
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
-
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsAVerticalConstrainedSizeFromTheFooterDelegateImplementation
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- FooterReferenceSizeTestDelegate *delegate = [[FooterReferenceSizeTestDelegate alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionVertical;
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-// Size implementation
-
-- (void)testThatItReturnsAVerticalConstrainedSizeFromTheHeaderProperty
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionVertical;
- layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsAVerticalConstrainedSizeFromTheFooterProperty
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionVertical;
- layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-// Horizontal
-
-- (void)testThatItReturnsAHorizontalConstrainedSizeFromTheHeaderDelegateImplementation
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsAHorizontalConstrainedSizeFromTheFooterDelegateImplementation
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- FooterReferenceSizeTestDelegate *delegate = [[FooterReferenceSizeTestDelegate alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-// Size implementation
-
-- (void)testThatItReturnsAHorizontalConstrainedSizeFromTheHeaderProperty
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
- layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.width));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsAHorizontalConstrainedSizeFromTheFooterProperty
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
-
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
- layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
-
- CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
-
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
- ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsZeroSizeWhenNoReferenceSizeIsImplemented
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeZero, CGSizeZero);
- XCTAssert(CGSizeEqualToSize(size.min, sizeCompare.min) && CGSizeEqualToSize(size.max, sizeCompare.max), @"should have a zero size");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-#pragma mark - #collectionView:supplementaryNodesOfKind:inSection:
-
-- (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheDelegate
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionHeader inSection:0];
- XCTAssert(count == 1, @"should have a header supplementary view");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheLayout
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionFooter inSection:0];
- XCTAssert(count == 1, @"should have a footer supplementary view");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItReturnsNoneWhenNoReferenceSizeIsImplemented
-{
- InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
- HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- collectionView.asyncDataSource = dataSource;
- collectionView.asyncDelegate = delegate;
- ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
- NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionFooter inSection:0];
- XCTAssert(count == 0, @"should not have a footer supplementary view");
-
- collectionView.asyncDataSource = nil;
- collectionView.asyncDelegate = nil;
-}
-
-- (void)testThatItThrowsIfNodeConstrainedSizeIsImplementedOnDataSourceButNotOnDelegateLayoutInspector
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionNode *node = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
- ASCollectionView *collectionView = node.view;
-
- id dataSourceAndDelegate = [OCMockObject mockForProtocol:@protocol(InspectorTestDataSourceDelegateProtocol)];
- ASSizeRange constrainedSize = ASSizeRangeMake(CGSizeZero, CGSizeZero);
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
- NSValue *value = [NSValue value:&constrainedSize withObjCType:@encode(ASSizeRange)];
- [[[dataSourceAndDelegate stub] andReturnValue:value] collectionNode:node constrainedSizeForItemAtIndexPath:indexPath];
- node.dataSource = dataSourceAndDelegate;
-
- id delegate = [InspectorTestDataSourceDelegateWithoutNodeConstrainedSize new];
- node.delegate = delegate;
-
- ASCollectionViewLayoutInspector *inspector = [[ASCollectionViewLayoutInspector alloc] init];
-
- collectionView.layoutInspector = inspector;
- XCTAssertThrows([inspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]);
-
- node.delegate = dataSourceAndDelegate;
- XCTAssertNoThrow([inspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]);
-}
-
-- (void)testThatItThrowsIfNodeConstrainedSizeIsImplementedOnDataSourceButNotOnDelegateFlowLayoutInspector
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
-
- ASCollectionNode *node = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
- ASCollectionView *collectionView = node.view;
- id dataSourceAndDelegate = [OCMockObject mockForProtocol:@protocol(InspectorTestDataSourceDelegateProtocol)];
- ASSizeRange constrainedSize = ASSizeRangeMake(CGSizeZero, CGSizeZero);
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
- NSValue *value = [NSValue value:&constrainedSize withObjCType:@encode(ASSizeRange)];
-
- [[[dataSourceAndDelegate stub] andReturnValue:value] collectionNode:node constrainedSizeForItemAtIndexPath:indexPath];
- node.dataSource = dataSourceAndDelegate;
- id delegate = [InspectorTestDataSourceDelegateWithoutNodeConstrainedSize new];
-
- node.delegate = delegate;
- ASCollectionViewFlowLayoutInspector *inspector = collectionView.layoutInspector;
-
- XCTAssertThrows([inspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]);
-
- node.delegate = dataSourceAndDelegate;
- XCTAssertNoThrow([inspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCollectionViewTests.mm b/submodules/AsyncDisplayKit/Tests/ASCollectionViewTests.mm
deleted file mode 100644
index 3ff5af4409..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCollectionViewTests.mm
+++ /dev/null
@@ -1,1173 +0,0 @@
-//
-// ASCollectionViewTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import "ASDisplayNodeTestsHelper.h"
-
-@interface ASTextCellNodeWithSetSelectedCounter : ASTextCellNode
-
-@property (nonatomic) NSUInteger setSelectedCounter;
-@property (nonatomic) NSUInteger applyLayoutAttributesCount;
-
-@end
-
-@implementation ASTextCellNodeWithSetSelectedCounter
-
-- (void)setSelected:(BOOL)selected
-{
- [super setSelected:selected];
- _setSelectedCounter++;
-}
-
-- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
-{
- _applyLayoutAttributesCount++;
-}
-
-@end
-
-@interface ASTestSectionContext : NSObject
-
-@property (nonatomic) NSInteger sectionIndex;
-@property (nonatomic) NSInteger sectionGeneration;
-
-@end
-
-@implementation ASTestSectionContext
-
-@synthesize sectionName = _sectionName, collectionView = _collectionView;
-
-@end
-
-@interface ASCollectionViewTestDelegate : NSObject
-
-@property (nonatomic) NSInteger sectionGeneration;
-@property (nonatomic) void(^willBeginBatchFetch)(ASBatchContext *);
-
-@end
-
-@implementation ASCollectionViewTestDelegate {
- @package
- std::vector _itemCounts;
-}
-
-- (id)initWithNumberOfSections:(NSInteger)numberOfSections numberOfItemsInSection:(NSInteger)numberOfItemsInSection {
- if (self = [super init]) {
- for (NSInteger i = 0; i < numberOfSections; i++) {
- _itemCounts.push_back(numberOfItemsInSection);
- }
- _sectionGeneration = 1;
- }
-
- return self;
-}
-
-- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath {
- ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new];
- textCellNode.text = indexPath.description;
-
- return textCellNode;
-}
-
-
-- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath {
- return ^{
- ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new];
- textCellNode.text = indexPath.description;
- return textCellNode;
- };
-}
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
- return _itemCounts.size();
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
- return _itemCounts[section];
-}
-
-- (id)collectionNode:(ASCollectionNode *)collectionNode contextForSection:(NSInteger)section
-{
- ASTestSectionContext *context = [[ASTestSectionContext alloc] init];
- context.sectionGeneration = _sectionGeneration;
- context.sectionIndex = section;
- return context;
-}
-
-- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
-{
- return CGSizeMake(100, 100);
-}
-
-- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
-{
- return [[ASTextCellNodeWithSetSelectedCounter alloc] init];
-}
-
-- (void)collectionNode:(ASCollectionNode *)collectionNode willBeginBatchFetchWithContext:(ASBatchContext *)context
-{
- if (_willBeginBatchFetch != nil) {
- _willBeginBatchFetch(context);
- } else {
- [context cancelBatchFetching];
- }
-}
-
-@end
-
-@interface ASCollectionViewTestController: UIViewController
-
-@property (nonatomic) ASCollectionViewTestDelegate *asyncDelegate;
-@property (nonatomic) ASCollectionView *collectionView;
-@property (nonatomic) ASCollectionNode *collectionNode;
-
-@end
-
-@implementation ASCollectionViewTestController
-
-- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Populate these immediately so that they're not unexpectedly nil during tests.
- self.asyncDelegate = [[ASCollectionViewTestDelegate alloc] initWithNumberOfSections:10 numberOfItemsInSection:10];
- id realLayout = [UICollectionViewFlowLayout new];
- id mockLayout = [OCMockObject partialMockForObject:realLayout];
- self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:mockLayout];
- self.collectionView = self.collectionNode.view;
- self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- self.collectionNode.dataSource = self.asyncDelegate;
- self.collectionNode.delegate = self.asyncDelegate;
-
- [self.collectionNode registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
- [self.view addSubview:self.collectionView];
- }
- return self;
-}
-
-@end
-
-@interface ASCollectionView (InternalTesting)
-
-- (NSArray *)dataController:(ASDataController *)dataController supplementaryNodeKindsInSections:(NSIndexSet *)sections;
-
-@end
-
-@interface ASCollectionViewTests : XCTestCase
-
-@end
-
-@implementation ASCollectionViewTests
-
-- (void)tearDown
-{
- // We can't prevent the system from retaining windows, but we can at least clear them out to avoid
- // pollution between test cases.
- for (UIWindow *window in [UIApplication sharedApplication].windows) {
- for (UIView *subview in window.subviews) {
- [subview removeFromSuperview];
- }
- }
- [super tearDown];
-}
-
-- (void)testDataSourceImplementsNecessaryMethods
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
-
- id dataSource = [NSObject new];
- XCTAssertThrows((collectionView.asyncDataSource = dataSource));
-
- dataSource = [OCMockObject niceMockForProtocol:@protocol(ASCollectionDataSource)];
- XCTAssertNoThrow((collectionView.asyncDataSource = dataSource));
-}
-
-- (void)testThatItSetsALayoutInspectorForFlowLayouts
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- XCTAssert(collectionView.layoutInspector != nil, @"should automatically set a layout delegate for flow layouts");
- XCTAssert([collectionView.layoutInspector isKindOfClass:[ASCollectionViewFlowLayoutInspector class]], @"should have a flow layout inspector by default");
-}
-
-- (void)testThatADefaultLayoutInspectorIsProvidedForCustomLayouts
-{
- UICollectionViewLayout *layout = [[UICollectionViewLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- XCTAssert(collectionView.layoutInspector != nil, @"should automatically set a layout delegate for flow layouts");
- XCTAssert([collectionView.layoutInspector isKindOfClass:[ASCollectionViewLayoutInspector class]], @"should have a default layout inspector by default");
-}
-
-- (void)testThatRegisteringASupplementaryNodeStoresItForIntrospection
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
- [collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
- XCTAssertEqualObjects([collectionView dataController:nil supplementaryNodeKindsInSections:[NSIndexSet indexSetWithIndex:0]], @[UICollectionElementKindSectionHeader]);
-}
-
-- (void)testReloadIfNeeded
-{
- __block ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- __block ASCollectionViewTestDelegate *del = testController.asyncDelegate;
- __block ASCollectionNode *cn = testController.collectionNode;
-
- void (^reset)() = ^void() {
- testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- del = testController.asyncDelegate;
- cn = testController.collectionNode;
- };
-
- // Check if the number of sections matches the data source
- XCTAssertEqual(cn.numberOfSections, del->_itemCounts.size(), @"Section count doesn't match the data source");
-
- // Reset everything and then check if numberOfItemsInSection matches the data source
- reset();
- XCTAssertEqual([cn numberOfItemsInSection:0], del->_itemCounts[0], @"Number of items in Section doesn't match the data source");
-
- // Reset and check if we can get the node corresponding to a specific indexPath
- reset();
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
- ASTextCellNodeWithSetSelectedCounter *node = (ASTextCellNodeWithSetSelectedCounter*)[cn nodeForItemAtIndexPath:indexPath];
- XCTAssertTrue([node.text isEqualToString:indexPath.description], @"Node's text should match the initial text it was created with");
-}
-
-- (void)testSelection
-{
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- [window setRootViewController:testController];
- [window makeKeyAndVisible];
-
- [testController.collectionNode reloadData];
- [testController.collectionNode waitUntilAllUpdatesAreProcessed];
- [testController.collectionView layoutIfNeeded];
-
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
- ASCellNode *node = [testController.collectionView nodeForItemAtIndexPath:indexPath];
-
- NSInteger setSelectedCount = 0;
- // selecting node should select cell
- node.selected = YES;
- ++setSelectedCount;
- XCTAssertTrue([[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath], @"Selecting node should update cell selection.");
-
- // deselecting node should deselect cell
- node.selected = NO;
- ++setSelectedCount;
- XCTAssertTrue([[testController.collectionView indexPathsForSelectedItems] isEqualToArray:@[]], @"Deselecting node should update cell selection.");
-
- // selecting cell via collectionNode should select node
- ++setSelectedCount;
- [testController.collectionNode selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
- XCTAssertTrue(node.isSelected == YES, @"Selecting cell should update node selection.");
-
- // deselecting cell via collectionNode should deselect node
- ++setSelectedCount;
- [testController.collectionNode deselectItemAtIndexPath:indexPath animated:NO];
- XCTAssertTrue(node.isSelected == NO, @"Deselecting cell should update node selection.");
-
- // select the cell again, scroll down and back up, and check that the state persisted
- [testController.collectionNode selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
- ++setSelectedCount;
- XCTAssertTrue(node.isSelected == YES, @"Selecting cell should update node selection.");
-
- testController.collectionNode.allowsMultipleSelection = YES;
-
- NSIndexPath *indexPath2 = [NSIndexPath indexPathForItem:1 inSection:0];
- ASCellNode *node2 = [testController.collectionView nodeForItemAtIndexPath:indexPath2];
-
- // selecting cell via collectionNode should select node
- [testController.collectionNode selectItemAtIndexPath:indexPath2 animated:NO scrollPosition:UICollectionViewScrollPositionNone];
- XCTAssertTrue(node2.isSelected == YES, @"Selecting cell should update node selection.");
-
- XCTAssertTrue([[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath] &&
- [[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath2],
- @"Selecting multiple cells should result in those cells being in the array of selectedItems.");
-
- // deselecting node should deselect cell
- node.selected = NO;
- ++setSelectedCount;
- XCTAssertTrue(![[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath] &&
- [[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath2], @"Deselecting node should update array of selectedItems.");
-
- node.selected = YES;
- ++setSelectedCount;
- XCTAssertTrue([[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath], @"Selecting node should update cell selection.");
-
- node2.selected = NO;
- XCTAssertTrue([[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath] &&
- ![[testController.collectionView indexPathsForSelectedItems] containsObject:indexPath2], @"Deselecting node should update array of selectedItems.");
-
- // reload cell (-prepareForReuse is called) & check that selected state is preserved
- [testController.collectionView setContentOffset:CGPointMake(0,testController.collectionView.bounds.size.height)];
- [testController.collectionView layoutIfNeeded];
- [testController.collectionView setContentOffset:CGPointMake(0,0)];
- [testController.collectionView layoutIfNeeded];
- XCTAssertTrue(node.isSelected == YES, @"Reloaded cell should preserve state.");
-
- // deselecting cell should deselect node
- UICollectionViewCell *cell = [testController.collectionView cellForItemAtIndexPath:indexPath];
- cell.selected = NO;
- XCTAssertTrue(node.isSelected == NO, @"Deselecting cell should update node selection.");
-
- // check setSelected not called extra times
- XCTAssertTrue([(ASTextCellNodeWithSetSelectedCounter *)node setSelectedCounter] == (setSelectedCount + 1), @"setSelected: should not be called on node multiple times.");
-}
-
-- (void)testTuningParametersWithExplicitRangeMode
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
-
- ASRangeTuningParameters minimumRenderParams = { .leadingBufferScreenfuls = 0.1, .trailingBufferScreenfuls = 0.1 };
- ASRangeTuningParameters minimumPreloadParams = { .leadingBufferScreenfuls = 0.1, .trailingBufferScreenfuls = 0.1 };
- ASRangeTuningParameters fullRenderParams = { .leadingBufferScreenfuls = 0.5, .trailingBufferScreenfuls = 0.5 };
- ASRangeTuningParameters fullPreloadParams = { .leadingBufferScreenfuls = 1, .trailingBufferScreenfuls = 0.5 };
-
- [collectionNode setTuningParameters:minimumRenderParams forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeDisplay];
- [collectionNode setTuningParameters:minimumPreloadParams forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypePreload];
- [collectionNode setTuningParameters:fullRenderParams forRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeDisplay];
- [collectionNode setTuningParameters:fullPreloadParams forRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypePreload];
-
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(minimumRenderParams,
- [collectionNode tuningParametersForRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypeDisplay]));
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(minimumPreloadParams,
- [collectionNode tuningParametersForRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypePreload]));
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(fullRenderParams,
- [collectionNode tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypeDisplay]));
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(fullPreloadParams,
- [collectionNode tuningParametersForRangeMode:ASLayoutRangeModeFull rangeType:ASLayoutRangeTypePreload]));
-}
-
-- (void)testTuningParameters
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
-
- ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.2, .trailingBufferScreenfuls = 3.2 };
- ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 4.3, .trailingBufferScreenfuls = 2.3 };
-
- [collectionView setTuningParameters:renderParams forRangeType:ASLayoutRangeTypeDisplay];
- [collectionView setTuningParameters:preloadParams forRangeType:ASLayoutRangeTypePreload];
-
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(renderParams, [collectionView tuningParametersForRangeType:ASLayoutRangeTypeDisplay]));
- XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(preloadParams, [collectionView tuningParametersForRangeType:ASLayoutRangeTypePreload]));
-}
-
-// Informations to test: https://github.com/TextureGroup/Texture/issues/1094
-- (void)testThatCollectionNodeCanHandleNilRangeController
-{
- UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
- [collectionNode recursivelySetInterfaceState:ASInterfaceStateDisplay];
- [collectionNode setHierarchyState:ASHierarchyStateRangeManaged];
- [collectionNode recursivelySetInterfaceState:ASInterfaceStateNone];
- ASCATransactionQueueWait(nil);
-}
-
-/**
- * This may seem silly, but we had issues where the runtime sometimes wouldn't correctly report
- * conformances declared on categories.
- */
-- (void)testThatCollectionNodeConformsToExpectedProtocols
-{
- ASCollectionNode *node = [[ASCollectionNode alloc] initWithFrame:CGRectZero collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
- XCTAssert([node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]);
-}
-
-#pragma mark - Update Validations
-
-#define updateValidationTestPrologue \
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];\
- __unused ASCollectionViewTestDelegate *del = testController.asyncDelegate;\
- __unused ASCollectionView *cv = testController.collectionView;\
- ASCollectionNode *cn = testController.collectionNode;\
- UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\
- [window makeKeyAndVisible]; \
- window.rootViewController = testController;\
- \
- [cn reloadData];\
- [cn waitUntilAllUpdatesAreProcessed]; \
- [testController.collectionView layoutIfNeeded];
-
-- (void)testThatSubmittingAValidInsertDoesNotThrowAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- del->_itemCounts[sectionCount - 1]++;
- XCTAssertNoThrow([cv insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:sectionCount - 1] ]]);
-}
-
-- (void)testThatSubmittingAValidReloadDoesNotThrowAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- XCTAssertNoThrow([cv reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:sectionCount - 1] ]]);
-}
-
-- (void)testThatSubmittingAnInvalidInsertThrowsAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- XCTAssertThrows([cv insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:sectionCount + 1] ]]);
-}
-
-- (void)testThatSubmittingAnInvalidDeleteThrowsAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- XCTAssertThrows([cv deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:sectionCount + 1] ]]);
-}
-
-- (void)testThatDeletingAndReloadingTheSameItemThrowsAnException
-{
- updateValidationTestPrologue
-
- XCTAssertThrows([cv performBatchUpdates:^{
- NSArray *indexPaths = @[ [NSIndexPath indexPathForItem:0 inSection:0] ];
- [cv deleteItemsAtIndexPaths:indexPaths];
- [cv reloadItemsAtIndexPaths:indexPaths];
- } completion:nil]);
-}
-
-- (void)testThatHavingAnIncorrectSectionCountThrowsAnException
-{
- updateValidationTestPrologue
-
- XCTAssertThrows([cv deleteSections:[NSIndexSet indexSetWithIndex:0]]);
-}
-
-- (void)testThatHavingAnIncorrectItemCountThrowsAnException
-{
- updateValidationTestPrologue
-
- XCTAssertThrows([cv deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:0] ]]);
-}
-
-- (void)testThatHavingAnIncorrectItemCountWithNoUpdatesThrowsAnException
-{
- updateValidationTestPrologue
-
- XCTAssertThrows([cv performBatchUpdates:^{
- del->_itemCounts[0]++;
- } completion:nil]);
-}
-
-- (void)testThatInsertingAnInvalidSectionThrowsAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- del->_itemCounts.push_back(10);
- XCTAssertThrows([cv performBatchUpdates:^{
- [cv insertSections:[NSIndexSet indexSetWithIndex:sectionCount + 1]];
- } completion:nil]);
-}
-
-- (void)testThatDeletingAndReloadingASectionThrowsAnException
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
-
- del->_itemCounts.pop_back();
- XCTAssertThrows([cv performBatchUpdates:^{
- NSIndexSet *sections = [NSIndexSet indexSetWithIndex:sectionCount - 1];
- [cv reloadSections:sections];
- [cv deleteSections:sections];
- } completion:nil]);
-}
-
-- (void)testCellNodeLayoutAttributes
-{
- updateValidationTestPrologue
- NSSet *nodeBatch1 = [NSSet setWithArray:[cn visibleNodes]];
- XCTAssertGreaterThan(nodeBatch1.count, 0);
-
- NSArray *visibleLayoutAttributesBatch1 = [cv.collectionViewLayout layoutAttributesForElementsInRect:cv.bounds];
- XCTAssertGreaterThan(visibleLayoutAttributesBatch1.count, 0);
-
- // Expect all visible nodes get 1 applyLayoutAttributes and have a non-nil value.
- for (ASTextCellNodeWithSetSelectedCounter *node in nodeBatch1) {
- XCTAssertEqual(node.applyLayoutAttributesCount, 1, @"Expected applyLayoutAttributes to be called exactly once for visible nodes.");
- XCTAssertNotNil(node.layoutAttributes, @"Expected layoutAttributes to be non-nil for visible cell node.");
- }
-
- for (UICollectionViewLayoutAttributes *layoutAttributes in visibleLayoutAttributesBatch1) {
- if (layoutAttributes.representedElementCategory != UICollectionElementCategorySupplementaryView) {
- continue;
- }
- ASTextCellNodeWithSetSelectedCounter *node = (ASTextCellNodeWithSetSelectedCounter *)[cv supplementaryNodeForElementKind:layoutAttributes.representedElementKind atIndexPath:layoutAttributes.indexPath];
- XCTAssertEqual(node.applyLayoutAttributesCount, 1, @"Expected applyLayoutAttributes to be called exactly once for visible supplementary nodes.");
- XCTAssertNotNil(node.layoutAttributes, @"Expected layoutAttributes to be non-nil for visible supplementary node.");
- }
-
- // Scroll to next batch of items.
- NSIndexPath *nextIP = [NSIndexPath indexPathForItem:nodeBatch1.count inSection:0];
- [cv scrollToItemAtIndexPath:nextIP atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
- [cv layoutIfNeeded];
-
- // Ensure we scrolled far enough that all the old ones are offscreen.
- NSSet *nodeBatch2 = [NSSet setWithArray:[cn visibleNodes]];
- XCTAssertFalse([nodeBatch1 intersectsSet:nodeBatch2], @"Expected to scroll far away enough that all nodes are replaced.");
-
- // Now the nodes are no longer visible, expect their layout attributes are nil but not another applyLayoutAttributes call.
- for (ASTextCellNodeWithSetSelectedCounter *node in nodeBatch1) {
- XCTAssertEqual(node.applyLayoutAttributesCount, 1, @"Expected applyLayoutAttributes to be called exactly once for visible nodes, even after node is removed.");
- XCTAssertNil(node.layoutAttributes, @"Expected layoutAttributes to be nil for removed cell node.");
- }
-
- for (UICollectionViewLayoutAttributes *layoutAttributes in visibleLayoutAttributesBatch1) {
- if (layoutAttributes.representedElementCategory != UICollectionElementCategorySupplementaryView) {
- continue;
- }
- ASTextCellNodeWithSetSelectedCounter *node = (ASTextCellNodeWithSetSelectedCounter *)[cv supplementaryNodeForElementKind:layoutAttributes.representedElementKind atIndexPath:layoutAttributes.indexPath];
- XCTAssertEqual(node.applyLayoutAttributesCount, 1, @"Expected applyLayoutAttributes to be called exactly once for visible supplementary nodes, even after node is removed.");
- XCTAssertNil(node.layoutAttributes, @"Expected layoutAttributes to be nil for removed supplementary node.");
- }
-}
-
-- (void)testCellNodeIndexPathConsistency
-{
- updateValidationTestPrologue
-
- // Test with a visible cell
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:2 inSection:0];
- ASCellNode *cell = [cn nodeForItemAtIndexPath:indexPath];
-
- // Check if cell's indexPath corresponds to the indexPath being tested
- XCTAssertTrue(cell.indexPath.section == indexPath.section && cell.indexPath.item == indexPath.item, @"Expected the cell's indexPath to be the same as the indexPath being tested.");
-
- // Remove an item prior to the cell's indexPath from the same section and check for indexPath consistency
- --del->_itemCounts[indexPath.section];
- [cn deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:indexPath.section]]];
- XCTAssertTrue(cell.indexPath.section == indexPath.section && cell.indexPath.item == (indexPath.item - 1), @"Expected the cell's indexPath to be updated once a cell with a lower index is deleted.");
-
- // Remove the section that includes the indexPath and check if the cell's indexPath is now nil
- del->_itemCounts.erase(del->_itemCounts.begin());
- [cn deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]];
- XCTAssertNil(cell.indexPath, @"Expected the cell's indexPath to be nil once the section that contains the node is deleted.");
-
- // Run the same tests but with a non-displayed cell
- indexPath = [NSIndexPath indexPathForItem:2 inSection:(del->_itemCounts.size() - 1)];
- cell = [cn nodeForItemAtIndexPath:indexPath];
-
- // Check if cell's indexPath corresponds to the indexPath being tested
- XCTAssertTrue(cell.indexPath.section == indexPath.section && cell.indexPath.item == indexPath.item, @"Expected the cell's indexPath to be the same as the indexPath in question.");
-
- // Remove an item prior to the cell's indexPath from the same section and check for indexPath consistency
- --del->_itemCounts[indexPath.section];
- [cn deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:indexPath.section]]];
- XCTAssertTrue(cell.indexPath.section == indexPath.section && cell.indexPath.item == (indexPath.item - 1), @"Expected the cell's indexPath to be updated once a cell with a lower index is deleted.");
-
- // Remove the section that includes the indexPath and check if the cell's indexPath is now nil
- del->_itemCounts.pop_back();
- [cn deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]];
- XCTAssertNil(cell.indexPath, @"Expected the cell's indexPath to be nil once the section that contains the node is deleted.");
-}
-
-/**
- * https://github.com/facebook/AsyncDisplayKit/issues/2011
- *
- * If this ever becomes a pain to maintain, drop it. The underlying issue is tested by testThatLayerBackedSubnodesAreMarkedInvisibleBeforeDeallocWhenSupernodesViewIsRemovedFromHierarchyWhileBeingRetained
- */
-- (void)testThatDisappearingSupplementariesWithLayerBackedNodesDontFailAssert
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- UICollectionViewLayout *layout = [[UICollectionViewFlowLayout alloc] init];
- ASCollectionNode *cn = [[ASCollectionNode alloc] initWithFrame:window.bounds collectionViewLayout:layout];
- ASCollectionView *cv = cn.view;
-
-
- __unused NSMutableSet *keepaliveNodes = [NSMutableSet set];
- id dataSource = [OCMockObject niceMockForProtocol:@protocol(ASCollectionDataSource)];
- static int nodeIdx = 0;
- [[[dataSource stub] andDo:^(NSInvocation *invocation) {
- __autoreleasing ASCellNode *suppNode = [[ASCellNode alloc] init];
- int thisNodeIdx = nodeIdx++;
- suppNode.debugName = [NSString stringWithFormat:@"Cell #%d", thisNodeIdx];
- [keepaliveNodes addObject:suppNode];
-
- ASDisplayNode *layerBacked = [[ASDisplayNode alloc] init];
- layerBacked.layerBacked = YES;
- layerBacked.debugName = [NSString stringWithFormat:@"Subnode #%d", thisNodeIdx];
- [suppNode addSubnode:layerBacked];
- [invocation setReturnValue:&suppNode];
- }] collectionNode:cn nodeForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:OCMOCK_ANY];
- [[[dataSource stub] andReturnValue:[NSNumber numberWithInteger:1]] numberOfSectionsInCollectionView:cv];
- cv.asyncDataSource = dataSource;
-
- id delegate = [OCMockObject niceMockForProtocol:@protocol(UICollectionViewDelegateFlowLayout)];
- [[[delegate stub] andReturnValue:[NSValue valueWithCGSize:CGSizeMake(100, 100)]] collectionView:cv layout:OCMOCK_ANY referenceSizeForHeaderInSection:0];
- cv.asyncDelegate = delegate;
-
- [cv registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
- [window addSubview:cv];
-
- [window makeKeyAndVisible];
-
- for (NSInteger i = 0; i < 2; i++) {
- // NOTE: reloadData and waitUntilAllUpdatesAreProcessed are not sufficient here!!
- XCTestExpectation *done = [self expectationWithDescription:[NSString stringWithFormat:@"Reload #%td complete", i]];
- [cn reloadDataWithCompletion:^{
- [done fulfill];
- }];
- [self waitForExpectationsWithTimeout:1 handler:nil];
- }
-
-}
-
-- (void)testThatNodeCalculatedSizesAreUpdatedBeforeFirstPrepareLayoutAfterRotation
-{
- updateValidationTestPrologue
- id layout = cv.collectionViewLayout;
- CGSize initialItemSize = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize;
- CGSize initialCVSize = cv.bounds.size;
-
- // Capture the node size before first call to prepareLayout after frame change.
- __block CGSize itemSizeAtFirstLayout = CGSizeZero;
- __block CGSize boundsSizeAtFirstLayout = CGSizeZero;
- [[[[layout expect] andDo:^(NSInvocation *) {
- itemSizeAtFirstLayout = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize;
- boundsSizeAtFirstLayout = [cv bounds].size;
- }] andForwardToRealObject] prepareLayout];
-
- // Rotate the device
- UIDeviceOrientation oldDeviceOrientation = [[UIDevice currentDevice] orientation];
- [[UIDevice currentDevice] setValue:@(UIDeviceOrientationLandscapeLeft) forKey:@"orientation"];
-
- CGSize finalItemSize = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize;
- CGSize finalCVSize = cv.bounds.size;
- XCTAssertNotEqualObjects(NSStringFromCGSize(initialItemSize), NSStringFromCGSize(itemSizeAtFirstLayout));
- XCTAssertNotEqualObjects(NSStringFromCGSize(initialCVSize), NSStringFromCGSize(boundsSizeAtFirstLayout));
- XCTAssertEqualObjects(NSStringFromCGSize(itemSizeAtFirstLayout), NSStringFromCGSize(finalItemSize));
- XCTAssertEqualObjects(NSStringFromCGSize(boundsSizeAtFirstLayout), NSStringFromCGSize(finalCVSize));
- [layout verify];
-
- // Teardown
- [[UIDevice currentDevice] setValue:@(oldDeviceOrientation) forKey:@"orientation"];
-}
-
-/**
- * See corresponding test in ASUICollectionViewTests
- *
- * @discussion Currently, we do not replicate UICollectionView's call order (outer, inner0, inner1, ...)
- * and instead call (inner0, inner1, outer, ...). This is because we primarily provide a
- * beginUpdates/endUpdatesWithCompletion: interface (like UITableView). With UICollectionView's
- * performBatchUpdates:completion:, the completion block is enqueued at -beginUpdates time.
- * With our tableView-like scheme, the completion block is provided at -endUpdates time
- * and it is naturally enqueued at this time. It is assumed that this is an acceptable deviation,
- * and that developers do not expect a particular completion order guarantee.
- */
-- (void)testThatNestedBatchCompletionsAreCalledInOrder
-{
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
-
- ASCollectionView *cv = testController.collectionView;
-
- XCTestExpectation *inner0 = [self expectationWithDescription:@"Inner completion 0 is called"];
- XCTestExpectation *inner1 = [self expectationWithDescription:@"Inner completion 1 is called"];
- XCTestExpectation *outer = [self expectationWithDescription:@"Outer completion is called"];
-
- NSMutableArray *completions = [NSMutableArray array];
-
- [cv performBatchUpdates:^{
- [cv performBatchUpdates:^{
-
- } completion:^(BOOL finished) {
- [completions addObject:inner0];
- [inner0 fulfill];
- }];
- [cv performBatchUpdates:^{
-
- } completion:^(BOOL finished) {
- [completions addObject:inner1];
- [inner1 fulfill];
- }];
- } completion:^(BOOL finished) {
- [completions addObject:outer];
- [outer fulfill];
- }];
-
- [self waitForExpectationsWithTimeout:5 handler:nil];
- XCTAssertEqualObjects(completions, (@[ inner0, inner1, outer ]), @"Expected completion order to be correct");
-}
-
-#pragma mark - ASSectionContext tests
-
-- (void)testThatSectionContextsAreCorrectAfterTheInitialLayout
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
- for (NSInteger section = 0; section < sectionCount; section++) {
- ASTestSectionContext *context = (ASTestSectionContext *)[cn contextForSection:section];
- XCTAssertNotNil(context);
- XCTAssertEqual(context.sectionGeneration, 1);
- XCTAssertEqual(context.sectionIndex, section);
- }
-}
-
-- (void)testThatSectionContextsAreCorrectAfterSectionMove
-{
- updateValidationTestPrologue
- NSInteger sectionCount = del->_itemCounts.size();
- NSInteger originalSection = sectionCount - 1;
- NSInteger toSection = 0;
-
- del.sectionGeneration++;
- [cv moveSection:originalSection toSection:toSection];
- [cv waitUntilAllUpdatesAreCommitted];
-
- // Only test left moving
- XCTAssertTrue(toSection < originalSection);
- ASTestSectionContext *movedSectionContext = (ASTestSectionContext *)[cn contextForSection:toSection];
- XCTAssertNotNil(movedSectionContext);
- // ASCollectionView currently splits a move operation to a pair of delete and insert ones.
- // So this movedSectionContext is newly loaded and thus is second generation.
- XCTAssertEqual(movedSectionContext.sectionGeneration, 2);
- XCTAssertEqual(movedSectionContext.sectionIndex, toSection);
-
- for (NSInteger section = toSection + 1; section <= originalSection && section < sectionCount; section++) {
- ASTestSectionContext *context = (ASTestSectionContext *)[cn contextForSection:section];
- XCTAssertNotNil(context);
- XCTAssertEqual(context.sectionGeneration, 1);
- // This section context was shifted to the right
- XCTAssertEqual(context.sectionIndex, (section - 1));
- }
-}
-
-- (void)testThatSectionContextsAreCorrectAfterReloadData
-{
- updateValidationTestPrologue
-
- del.sectionGeneration++;
- [cn reloadData];
- [cn waitUntilAllUpdatesAreProcessed];
-
- NSInteger sectionCount = del->_itemCounts.size();
- for (NSInteger section = 0; section < sectionCount; section++) {
- ASTestSectionContext *context = (ASTestSectionContext *)[cn contextForSection:section];
- XCTAssertNotNil(context);
- XCTAssertEqual(context.sectionGeneration, 2);
- XCTAssertEqual(context.sectionIndex, section);
- }
-}
-
-- (void)testThatSectionContextsAreCorrectAfterReloadASection
-{
- updateValidationTestPrologue
- NSInteger sectionToReload = 0;
-
- del.sectionGeneration++;
- [cv reloadSections:[NSIndexSet indexSetWithIndex:sectionToReload]];
- [cv waitUntilAllUpdatesAreCommitted];
-
- NSInteger sectionCount = del->_itemCounts.size();
- for (NSInteger section = 0; section < sectionCount; section++) {
- ASTestSectionContext *context = (ASTestSectionContext *)[cn contextForSection:section];
- XCTAssertNotNil(context);
- XCTAssertEqual(context.sectionGeneration, section != sectionToReload ? 1 : 2);
- XCTAssertEqual(context.sectionIndex, section);
- }
-}
-
-/// See the same test in ASUICollectionViewTests for the reference behavior.
-- (void)testThatIssuingAnUpdateBeforeInitialReloadIsAcceptable
-{
- ASCollectionViewTestDelegate *del = [[ASCollectionViewTestDelegate alloc] initWithNumberOfSections:0 numberOfItemsInSection:0];
- ASCollectionView *cv = [[ASCollectionView alloc] initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
- cv.asyncDataSource = del;
- cv.asyncDelegate = del;
-
- // Add a section to the data source
- del->_itemCounts.push_back(0);
- // Attempt to insert section into collection view. We ignore it to workaround
- // the bug demonstrated by
- // ASUICollectionViewTests.testThatIssuingAnUpdateBeforeInitialReloadIsUnacceptable
- XCTAssertNoThrow([cv insertSections:[NSIndexSet indexSetWithIndex:0]]);
-}
-
-- (void)testThatNodeAtIndexPathIsCorrectImmediatelyAfterSubmittingUpdate
-{
- updateValidationTestPrologue
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
-
- // Insert an item and assert nodeForItemAtIndexPath: immediately returns new node
- ASCellNode *oldNode = [cn nodeForItemAtIndexPath:indexPath];
- XCTAssertNotNil(oldNode);
- del->_itemCounts[0] += 1;
- [cv insertItemsAtIndexPaths:@[ indexPath ]];
- ASCellNode *newNode = [cn nodeForItemAtIndexPath:indexPath];
- XCTAssertNotNil(newNode);
- XCTAssertNotEqualObjects(oldNode, newNode);
-
- // Delete all sections and assert nodeForItemAtIndexPath: immediately returns nil
- NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, del->_itemCounts.size())];
- del->_itemCounts.clear();
- [cv deleteSections:sections];
- XCTAssertNil([cn nodeForItemAtIndexPath:indexPath]);
-}
-
-- (void)DISABLED_testThatSupplementaryNodeAtIndexPathIsCorrectImmediatelyAfterSubmittingUpdate
-{
- updateValidationTestPrologue
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
- ASCellNode *oldHeader = [cv supplementaryNodeForElementKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
- XCTAssertNotNil(oldHeader);
-
- // Reload the section and ensure that the new header is loaded
- [cv reloadSections:[NSIndexSet indexSetWithIndex:0]];
- ASCellNode *newHeader = [cv supplementaryNodeForElementKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
- XCTAssertNotNil(newHeader);
- XCTAssertNotEqualObjects(oldHeader, newHeader);
-}
-
-- (void)testThatNilBatchUpdatesCanBeSubmitted
-{
- __block ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- __block ASCollectionNode *cn = testController.collectionNode;
-
- // Passing nil blocks should not crash
- [cn performBatchUpdates:nil completion:nil];
- [cn performBatchAnimated:NO updates:nil completion:nil];
-}
-
-- (void)testThatDeletedItemsAreMarkedInvisible
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- window.rootViewController = testController;
-
- __block NSInteger itemCount = 1;
- testController.asyncDelegate->_itemCounts = {itemCount};
- [window makeKeyAndVisible];
- [window layoutIfNeeded];
-
- ASCollectionNode *cn = testController.collectionNode;
- [cn waitUntilAllUpdatesAreProcessed];
- [cn.view layoutIfNeeded];
- ASCellNode *node = [cn nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
- ASCATransactionQueueWait(nil);
- XCTAssertTrue(node.visible);
- testController.asyncDelegate->_itemCounts = {0};
- [cn deleteItemsAtIndexPaths: @[[NSIndexPath indexPathForItem:0 inSection:0]]];
- [self expectationForPredicate:[NSPredicate predicateWithFormat:@"visible = NO"] evaluatedWithObject:node handler:nil];
- [self waitForExpectationsWithTimeout:3 handler:nil];
-}
-
-- (void)disabled_testThatMultipleBatchFetchesDontHappenUnnecessarily
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- window.rootViewController = testController;
-
- // Start with 1 item so that our content does not fill bounds.
- __block NSInteger itemCount = 1;
- testController.asyncDelegate->_itemCounts = {itemCount};
- [window makeKeyAndVisible];
- [window layoutIfNeeded];
-
- ASCollectionNode *cn = testController.collectionNode;
- [cn waitUntilAllUpdatesAreProcessed];
- XCTAssertGreaterThan(cn.bounds.size.height, cn.view.contentSize.height, @"Expected initial data not to fill collection view area.");
-
- __block NSUInteger batchFetchCount = 0;
- XCTestExpectation *expectation = [self expectationWithDescription:@"Batch fetching completed and then some"];
- __weak ASCollectionViewTestController *weakController = testController;
- testController.asyncDelegate.willBeginBatchFetch = ^(ASBatchContext *context) {
-
- // Ensure only 1 batch fetch happens
- batchFetchCount += 1;
- if (batchFetchCount > 1) {
- XCTFail(@"Too many batch fetches!");
- return;
- }
-
- dispatch_async(dispatch_get_main_queue(), ^{
- // Up the item count to 1000 so that we're well beyond the
- // edge of the collection view and not ready for another batch fetch.
- NSMutableArray *indexPaths = [NSMutableArray array];
- for (; itemCount < 1000; itemCount++) {
- [indexPaths addObject:[NSIndexPath indexPathForItem:itemCount inSection:0]];
- }
- weakController.asyncDelegate->_itemCounts = {itemCount};
- [cn insertItemsAtIndexPaths:indexPaths];
- [context completeBatchFetching:YES];
-
- // Let the run loop turn before we consider the test passed.
- dispatch_async(dispatch_get_main_queue(), ^{
- [expectation fulfill];
- });
- });
- };
- [self waitForExpectationsWithTimeout:3 handler:nil];
-}
-
-- (void)testThatBatchFetchHappensForEmptyCollection
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- window.rootViewController = testController;
-
- testController.asyncDelegate->_itemCounts = {};
- [window makeKeyAndVisible];
- [window layoutIfNeeded];
-
- ASCollectionNode *cn = testController.collectionNode;
- [cn waitUntilAllUpdatesAreProcessed];
-
- __block NSUInteger batchFetchCount = 0;
- XCTestExpectation *e = [self expectationWithDescription:@"Batch fetching completed"];
- testController.asyncDelegate.willBeginBatchFetch = ^(ASBatchContext *context) {
- // Ensure only 1 batch fetch happens
- batchFetchCount += 1;
- if (batchFetchCount > 1) {
- XCTFail(@"Too many batch fetches!");
- return;
- }
- [e fulfill];
- };
- [self waitForExpectationsWithTimeout:3 handler:nil];
-}
-
-- (void)testThatWeBatchFetchUntilContentRequirementIsMet_Animated
-{
- [self _primitiveBatchFetchingFillTestAnimated:YES visible:YES controller:nil];
-}
-
-- (void)testThatWeBatchFetchUntilContentRequirementIsMet_Nonanimated
-{
- [self _primitiveBatchFetchingFillTestAnimated:NO visible:YES controller:nil];
-}
-
-- (void)testThatWeBatchFetchUntilContentRequirementIsMet_Invisible
-{
- [self _primitiveBatchFetchingFillTestAnimated:NO visible:NO controller:nil];
-}
-
-- (void)testThatWhenWeBecomeVisibleWeWillFetchAdditionalContent
-{
- ASCollectionViewTestController *ctrl = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- // Start with 1 empty section
- ctrl.asyncDelegate->_itemCounts = {0};
- [self _primitiveBatchFetchingFillTestAnimated:NO visible:NO controller:ctrl];
- XCTAssertGreaterThan([ctrl.collectionNode numberOfItemsInSection:0], 0);
- [self _primitiveBatchFetchingFillTestAnimated:NO visible:YES controller:ctrl];
-}
-
-- (void)_primitiveBatchFetchingFillTestAnimated:(BOOL)animated visible:(BOOL)visible controller:(nullable ASCollectionViewTestController *)testController
-{
- if (testController == nil) {
- testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- // Start with 1 empty section
- testController.asyncDelegate->_itemCounts = {0};
- }
- ASCollectionNode *cn = testController.collectionNode;
-
- UIWindow *window = nil;
- UIView *view = nil;
- if (visible) {
- window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- view = window;
- } else {
- view = cn.view;
- view.frame = [UIScreen mainScreen].bounds;
- }
-
- XCTestExpectation *expectation = [self expectationWithDescription:@"Completed all batch fetches"];
- __weak ASCollectionViewTestController *weakController = testController;
- __block NSInteger batchFetchCount = 0;
- testController.asyncDelegate.willBeginBatchFetch = ^(ASBatchContext *context) {
- dispatch_async(dispatch_get_main_queue(), ^{
- NSInteger fetchIndex = batchFetchCount++;
-
- NSInteger itemCount = weakController.asyncDelegate->_itemCounts[0];
- weakController.asyncDelegate->_itemCounts[0] = (itemCount + 1);
- if (animated) {
- [cn insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:itemCount inSection:0] ]];
- } else {
- [cn performBatchAnimated:NO updates:^{
- [cn insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:itemCount inSection:0] ]];
- } completion:nil];
- }
-
- [context completeBatchFetching:YES];
-
- // If no more batch fetches have happened in 1 second, assume we're done.
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (fetchIndex == batchFetchCount - 1) {
- [expectation fulfill];
- }
- });
- });
- };
- window.rootViewController = testController;
-
- [window makeKeyAndVisible];
- // Trigger the initial reload to start
- [view layoutIfNeeded];
-
- // Wait for ASDK reload to finish
- [cn waitUntilAllUpdatesAreProcessed];
- // Force UIKit to read updated data & range controller to update and account for it
- [cn.view layoutIfNeeded];
- [self waitForExpectationsWithTimeout:60 handler:nil];
-
- CGFloat contentHeight = cn.view.contentSize.height;
- CGFloat requiredContentHeight;
- CGFloat itemHeight = [cn.view layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].size.height;
- if (visible) {
- requiredContentHeight = CGRectGetMaxY(cn.bounds) + CGRectGetHeight(cn.bounds) * cn.view.leadingScreensForBatching;
- } else {
- requiredContentHeight = CGRectGetMaxY(cn.bounds);
- }
- XCTAssertGreaterThan(batchFetchCount, 2);
- XCTAssertGreaterThanOrEqual(contentHeight, requiredContentHeight, @"Loaded too little content.");
- XCTAssertLessThanOrEqual(contentHeight, requiredContentHeight + 3 * itemHeight, @"Loaded too much content.");
-}
-
-- (void)testInitialRangeBounds
-{
- [self testInitialRangeBoundsWithCellLayoutMode:ASCellLayoutModeNone
- shouldWaitUntilAllUpdatesAreProcessed:YES];
-}
-
-- (void)testInitialRangeBoundsCellLayoutModeAlwaysAsync
-{
- [self testInitialRangeBoundsWithCellLayoutMode:ASCellLayoutModeAlwaysAsync
- shouldWaitUntilAllUpdatesAreProcessed:YES];
-}
-
-- (void)testInitialRangeBoundsWithCellLayoutMode:(ASCellLayoutMode)cellLayoutMode
- shouldWaitUntilAllUpdatesAreProcessed:(BOOL)shouldWait
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- ASCollectionNode *cn = testController.collectionNode;
- cn.cellLayoutMode = cellLayoutMode;
- [cn setTuningParameters:{ .leadingBufferScreenfuls = 2, .trailingBufferScreenfuls = 0 } forRangeMode:ASLayoutRangeModeMinimum rangeType:ASLayoutRangeTypePreload];
- window.rootViewController = testController;
-
- [testController.collectionNode.collectionViewLayout invalidateLayout];
- [testController.collectionNode.collectionViewLayout prepareLayout];
-
- [window makeKeyAndVisible];
- // Trigger the initial reload to start
- [window layoutIfNeeded];
-
- if (shouldWait) {
- XCTAssertTrue(cn.isProcessingUpdates, @"ASCollectionNode should still be processing updates after initial layoutIfNeeded call (reloadData)");
-
- [cn onDidFinishProcessingUpdates:^{
- XCTAssertTrue(!cn.isProcessingUpdates, @"ASCollectionNode should no longer be processing updates inside -onDidFinishProcessingUpdates: block");
- }];
-
- // Wait for ASDK reload to finish
- [cn waitUntilAllUpdatesAreProcessed];
- }
-
- XCTAssertTrue(!cn.isProcessingUpdates, @"ASCollectionNode should no longer be processing updates after -wait call");
-
- // Force UIKit to read updated data & range controller to update and account for it
- [cn.view layoutIfNeeded];
-
- CGRect preloadBounds = ({
- CGRect r = CGRectNull;
- for (NSInteger s = 0; s < cn.numberOfSections; s++) {
- NSInteger c = [cn numberOfItemsInSection:s];
- for (NSInteger i = 0; i < c; i++) {
- NSIndexPath *ip = [NSIndexPath indexPathForItem:i inSection:s];
- ASCellNode *node = [cn nodeForItemAtIndexPath:ip];
- ASCATransactionQueueWait(nil);
- if (node.inPreloadState) {
- CGRect frame = [cn.view layoutAttributesForItemAtIndexPath:ip].frame;
- r = CGRectUnion(r, frame);
- }
- }
- }
- r;
- });
- CGFloat expectedHeight = cn.bounds.size.height * 3;
- XCTAssertEqualWithAccuracy(CGRectGetHeight(preloadBounds), expectedHeight, expectedHeight * 0.1);
- XCTAssertEqual([[cn valueForKeyPath:@"rangeController.currentRangeMode"] integerValue], ASLayoutRangeModeMinimum, @"Expected range mode to be minimum before scrolling begins.");
-}
-
-- (void)testTraitCollectionChangesMidUpdate
-{
- CGRect screenBounds = [UIScreen mainScreen].bounds;
- UIWindow *window = [[UIWindow alloc] initWithFrame:screenBounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- ASCollectionNode *cn = testController.collectionNode;
- window.rootViewController = testController;
-
- [window makeKeyAndVisible];
- // Trigger the initial reload to start
- [window layoutIfNeeded];
-
- // The initial reload is async, changing the trait collection here should be "mid-update"
- ASPrimitiveTraitCollection traitCollection = ASPrimitiveTraitCollectionMakeDefault();
- traitCollection.displayScale = cn.primitiveTraitCollection.displayScale + 1; // Just a dummy change
- traitCollection.containerSize = screenBounds.size;
- cn.primitiveTraitCollection = traitCollection;
-
- [cn waitUntilAllUpdatesAreProcessed];
- [cn.view layoutIfNeeded];
-
- // Assert that the new trait collection is picked up by all cell nodes, including ones that were not allocated but are forced to allocate now
- for (NSInteger s = 0; s < cn.numberOfSections; s++) {
- NSInteger c = [cn numberOfItemsInSection:s];
- for (NSInteger i = 0; i < c; i++) {
- NSIndexPath *ip = [NSIndexPath indexPathForItem:i inSection:s];
- ASCellNode *node = [cn.view nodeForItemAtIndexPath:ip];
- XCTAssertTrue(ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(traitCollection, node.primitiveTraitCollection));
- }
- }
-}
-
-/**
- * This tests an issue where, since subnode insertions aren't applied until the UIKit layout pass,
- * which we trigger during the display phase, subnodes like network image nodes are not preloading
- * until this layout pass happens which is too late.
- */
-- (void)DISABLED_testThatAutomaticallyManagedSubnodesGetPreloadCallBeforeDisplay
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASCollectionViewTestController *testController = [[ASCollectionViewTestController alloc] initWithNibName:nil bundle:nil];
- window.rootViewController = testController;
- ASCollectionNode *cn = testController.collectionNode;
-
- __block NSInteger itemCount = 100;
- testController.asyncDelegate->_itemCounts = {itemCount};
- [window makeKeyAndVisible];
- [window layoutIfNeeded];
-
- [cn waitUntilAllUpdatesAreProcessed];
- for (NSInteger i = 0; i < itemCount; i++) {
- ASTextCellNodeWithSetSelectedCounter *node = [cn nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
- XCTAssert(node.automaticallyManagesSubnodes, @"Expected test cell node to use automatic subnode management. Can modify the test with a different class if needed.");
- ASDisplayNode *subnode = node.textNode;
- XCTAssertEqualObjects(NSStringFromASInterfaceState(subnode.interfaceState), NSStringFromASInterfaceState(node.interfaceState), @"Subtree interface state should match cell node interface state for ASM nodes.");
- XCTAssert(node.inDisplayState || !node.nodeLoaded, @"Only nodes in the display range should be loaded.");
- }
-
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCollectionViewThrashTests.mm b/submodules/AsyncDisplayKit/Tests/ASCollectionViewThrashTests.mm
deleted file mode 100644
index 4650639d1f..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCollectionViewThrashTests.mm
+++ /dev/null
@@ -1,217 +0,0 @@
-//
-// ASCollectionViewThrashTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-
-#import "ASThrashUtility.h"
-
-@interface ASCollectionViewThrashTests : XCTestCase
-
-@end
-
-@implementation ASCollectionViewThrashTests
-{
- // The current update, which will be logged in case of a failure.
- ASThrashUpdate *_update;
- BOOL _failed;
-}
-
-- (void)tearDown
-{
- if (_failed && _update != nil) {
- NSLog(@"Failed update %@: %@", _update, _update.logFriendlyBase64Representation);
- }
- _failed = NO;
- _update = nil;
-}
-
-// NOTE: Despite the documentation, this is not always called if an exception is caught.
-- (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber expected:(BOOL)expected
-{
- _failed = YES;
- [super recordFailureWithDescription:description inFile:filePath atLine:lineNumber expected:expected];
-}
-
-- (void)verifyDataSource:(ASThrashDataSource *)ds
-{
- CollectionView *collectionView = ds.collectionView;
- NSArray *data = [ds data];
- for (NSInteger i = 0; i < collectionView.numberOfSections; i++) {
- XCTAssertEqual([collectionView numberOfItemsInSection:i], data[i].items.count);
-
- for (NSInteger j = 0; j < [collectionView numberOfItemsInSection:i]; j++) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i];
- ASThrashTestItem *item = data[i].items[j];
- ASThrashTestNode *node = (ASThrashTestNode *)[collectionView nodeForItemAtIndexPath:indexPath];
- XCTAssertEqualObjects(node.item, item, @"Wrong node at index path %@", indexPath);
- }
- }
-}
-
-#pragma mark Test Methods
-
-- (void)testInitialDataRead
-{
- ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:[ASThrashTestSection sectionsWithCount:kInitialSectionCount]];
- [self verifyDataSource:ds];
-}
-
-/// Replays the Base64 representation of an ASThrashUpdate from "ASThrashTestRecordedCase" file
-- (void)testRecordedThrashCase
-{
- NSURL *caseURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"ASThrashTestRecordedCase" withExtension:nil subdirectory:@"TestResources"];
- NSString *base64 = [NSString stringWithContentsOfURL:caseURL encoding:NSUTF8StringEncoding error:NULL];
-
- _update = [ASThrashUpdate thrashUpdateWithBase64String:base64];
- if (_update == nil) {
- return;
- }
-
- ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:_update.oldData];
- [self applyUpdateUsingBatchUpdates:_update
- toDataSource:ds
- animated:NO
- useXCTestWait:YES];
- [self verifyDataSource:ds];
-}
-
-- (void)testThrashingWildly
-{
- for (NSInteger i = 0; i < kThrashingIterationCount; i++) {
- [self setUp];
- @autoreleasepool {
- NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
- _update = [[ASThrashUpdate alloc] initWithData:sections];
- ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections];
-
- [self applyUpdateUsingBatchUpdates:_update
- toDataSource:ds
- animated:NO
- useXCTestWait:NO];
- [self verifyDataSource:ds];
- [self expectationForPredicate:[ds predicateForDeallocatedHierarchy] evaluatedWithObject:(id)kCFNull handler:nil];
- }
- [self waitForExpectationsWithTimeout:3 handler:nil];
-
- [self tearDown];
- }
-}
-
-- (void)testThrashingWildlyOnSameCollectionView
-{
- XCTestExpectation *expectation = [self expectationWithDescription:@"last test ran"];
- ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:nil];
- for (NSInteger i = 0; i < 1000; i++) {
- [self setUp];
- @autoreleasepool {
- NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
- _update = [[ASThrashUpdate alloc] initWithData:sections];
- [ds setData:sections];
- [ds.collectionView reloadData];
-
- [self applyUpdateUsingBatchUpdates:_update
- toDataSource:ds
- animated:NO
- useXCTestWait:NO];
- [self verifyDataSource:ds];
- if (i == 999) {
- [expectation fulfill];
- }
- }
-
- [self tearDown];
- }
- [self waitForExpectationsWithTimeout:3 handler:nil];
-}
-
-- (void)testThrashingWildlyDispatchWildly
-{
- XCTestExpectation *expectation = [self expectationWithDescription:@"last test ran"];
- for (NSInteger i = 0; i < kThrashingIterationCount; i++) {
- [self setUp];
- @autoreleasepool {
- dispatch_async(dispatch_get_main_queue(), ^{
- NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
- _update = [[ASThrashUpdate alloc] initWithData:sections];
- ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections];
-
- [self applyUpdateUsingBatchUpdates:_update
- toDataSource:ds
- animated:NO
- useXCTestWait:NO];
- [self verifyDataSource:ds];
- if (i == kThrashingIterationCount-1) {
- [expectation fulfill];
- }
- });
- }
-
- [self tearDown];
- }
-
- [self waitForExpectationsWithTimeout:100 handler:nil];
-}
-
-#pragma mark Helpers
-
-- (void)applyUpdateUsingBatchUpdates:(ASThrashUpdate *)update
- toDataSource:(ASThrashDataSource *)dataSource animated:(BOOL)animated
- useXCTestWait:(BOOL)wait
-{
- CollectionView *collectionView = dataSource.collectionView;
-
- XCTestExpectation *expectation;
- if (wait) {
- expectation = [self expectationWithDescription:@"Wait for collection view to update"];
- }
-
- void (^updateBlock)() = ^ void (){
- dataSource.data = update.data;
-
- [collectionView insertSections:update.insertedSectionIndexes];
- [collectionView deleteSections:update.deletedSectionIndexes];
- [collectionView reloadSections:update.replacedSectionIndexes];
-
- [update.insertedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
- NSArray *indexPaths = [indexes indexPathsInSection:idx];
- [collectionView insertItemsAtIndexPaths:indexPaths];
- }];
-
- [update.deletedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
- NSArray *indexPaths = [indexes indexPathsInSection:idx];
- [collectionView deleteItemsAtIndexPaths:indexPaths];
- }];
-
- [update.replacedItemIndexes enumerateObjectsUsingBlock:^(NSMutableIndexSet * _Nonnull indexes, NSUInteger idx, BOOL * _Nonnull stop) {
- NSArray *indexPaths = [indexes indexPathsInSection:idx];
- [collectionView reloadItemsAtIndexPaths:indexPaths];
- }];
- };
-
- @try {
- [collectionView performBatchAnimated:animated
- updates:updateBlock
- completion:^(BOOL finished) {
- [expectation fulfill];
- }];
- } @catch (NSException *exception) {
- _failed = YES;
- XCTFail("TEST FAILED");
- @throw exception;
- }
-
- if (wait) {
- [self waitForExpectationsWithTimeout:1 handler:nil];
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCollectionsTests.mm b/submodules/AsyncDisplayKit/Tests/ASCollectionsTests.mm
deleted file mode 100644
index ae0313d78c..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCollectionsTests.mm
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// ASCollectionsTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-@interface ASCollectionsTests : XCTestCase
-
-@end
-
-@implementation ASCollectionsTests
-
-- (void)testTransferArray {
- id objs[2];
- objs[0] = [NSObject new];
- id o0 = objs[0];
- objs[1] = [NSObject new];
- __weak id w0 = objs[0];
- __weak id w1 = objs[1];
- CFTypeRef cf0 = (__bridge CFTypeRef)objs[0];
- CFTypeRef cf1 = (__bridge CFTypeRef)objs[1];
- XCTAssertEqual(CFGetRetainCount(cf0), 2);
- XCTAssertEqual(CFGetRetainCount(cf1), 1);
- NSArray *arr = [NSArray arrayByTransferring:objs count:2];
- XCTAssertNil(objs[0]);
- XCTAssertNil(objs[1]);
- XCTAssertEqual(CFGetRetainCount(cf0), 2);
- XCTAssertEqual(CFGetRetainCount(cf1), 1);
- NSArray *immutableCopy = [arr copy];
- XCTAssertEqual(immutableCopy, arr);
- XCTAssertEqual(CFGetRetainCount(cf0), 2);
- XCTAssertEqual(CFGetRetainCount(cf1), 1);
- NSMutableArray *mc = [arr mutableCopy];
- XCTAssertEqual(CFGetRetainCount(cf0), 3);
- XCTAssertEqual(CFGetRetainCount(cf1), 2);
- arr = nil;
- immutableCopy = nil;
- XCTAssertEqual(CFGetRetainCount(cf0), 2);
- XCTAssertEqual(CFGetRetainCount(cf1), 1);
- [mc removeObjectAtIndex:0];
- XCTAssertEqual(CFGetRetainCount(cf0), 1);
- XCTAssertEqual(CFGetRetainCount(cf1), 1);
- [mc removeObjectAtIndex:0];
- XCTAssertEqual(CFGetRetainCount(cf0), 1);
- XCTAssertNil(w1);
- o0 = nil;
- XCTAssertNil(w0);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASConfigurationTests.mm b/submodules/AsyncDisplayKit/Tests/ASConfigurationTests.mm
deleted file mode 100644
index 6952924851..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASConfigurationTests.mm
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// ASConfigurationTests.m
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-#import
-#import
-
-#import "ASTestCase.h"
-
-static ASExperimentalFeatures features[] = {
- ASExperimentalGraphicsContexts,
-#if AS_ENABLE_TEXTNODE
- ASExperimentalTextNode,
-#endif
- ASExperimentalInterfaceStateCoalescing,
- ASExperimentalUnfairLock,
- ASExperimentalLayerDefaults,
- ASExperimentalCollectionTeardown,
- ASExperimentalFramesetterCache,
- ASExperimentalSkipClearData,
- ASExperimentalDidEnterPreloadSkipASMLayout,
- ASExperimentalDisableAccessibilityCache,
- ASExperimentalDispatchApply,
- ASExperimentalImageDownloaderPriority,
- ASExperimentalTextDrawing
-};
-
-@interface ASConfigurationTests : ASTestCase
-
-@end
-
-@implementation ASConfigurationTests {
- void (^onActivate)(ASConfigurationTests *self, ASExperimentalFeatures feature);
-}
-
-+ (NSArray *)names {
- return @[
- @"exp_graphics_contexts",
- @"exp_text_node",
- @"exp_interface_state_coalesce",
- @"exp_unfair_lock",
- @"exp_infer_layer_defaults",
- @"exp_collection_teardown",
- @"exp_framesetter_cache",
- @"exp_skip_clear_data",
- @"exp_did_enter_preload_skip_asm_layout",
- @"exp_disable_a11y_cache",
- @"exp_dispatch_apply",
- @"exp_image_downloader_priority",
- @"exp_text_drawing"
- ];
-}
-
-- (ASExperimentalFeatures)allFeatures {
- ASExperimentalFeatures allFeatures = 0;
- for (int i = 0; i < sizeof(features)/sizeof(ASExperimentalFeatures); i++) {
- allFeatures |= features[i];
- }
- return allFeatures;
-}
-
-#if AS_ENABLE_TEXTNODE
-
-- (void)testExperimentalFeatureConfig
-{
- // Set the config
- ASConfiguration *config = [[ASConfiguration alloc] initWithDictionary:nil];
- config.experimentalFeatures = ASExperimentalGraphicsContexts;
- config.delegate = self;
- [ASConfigurationManager test_resetWithConfiguration:config];
-
- // Set an expectation for a callback, and assert we only get one.
- XCTestExpectation *e = [self expectationWithDescription:@"Callbacks done."];
- e.expectedFulfillmentCount = 2;
- e.assertForOverFulfill = YES;
- onActivate = ^(ASConfigurationTests *self, ASExperimentalFeatures feature) {
- [e fulfill];
- };
-
- // Now activate the graphics experiment and expect it works.
- XCTAssertTrue(ASActivateExperimentalFeature(ASExperimentalGraphicsContexts));
- // We should get a callback here
- // Now activate text node and expect it fails.
- XCTAssertFalse(ASActivateExperimentalFeature(ASExperimentalTextNode));
- // But we should get another callback.
- [self waitForExpectationsWithTimeout:3 handler:nil];
-}
-
-#endif
-
-- (void)textureDidActivateExperimentalFeatures:(ASExperimentalFeatures)feature
-{
- if (onActivate) {
- onActivate(self, feature);
- }
-}
-
-- (void)testMappingNamesToFlags
-{
- // Throw in a bad bit.
- ASExperimentalFeatures allFeatures = [self allFeatures];
- ASExperimentalFeatures featuresWithBadBit = allFeatures | (1 << 22);
- NSArray *expectedNames = [ASConfigurationTests names];
- XCTAssertEqualObjects(expectedNames, ASExperimentalFeaturesGetNames(featuresWithBadBit));
-}
-
-- (void)testMappingFlagsFromNames
-{
- // Throw in a bad name.
- NSMutableArray *allNames = [[NSMutableArray alloc] initWithArray:[ASConfigurationTests names]];
- [allNames addObject:@"__invalid_name"];
- ASExperimentalFeatures expected = [self allFeatures];
- XCTAssertEqual(expected, ASExperimentalFeaturesFromArray(allNames));
-}
-
-- (void)testFlagMatchName
-{
- NSArray *names = [ASConfigurationTests names];
- for (NSInteger i = 0; i < names.count; i++) {
- XCTAssertEqual(features[i], ASExperimentalFeaturesFromArray(@[names[i]]));
- }
-}
-
-- (void)testNameMatchFlag {
- NSArray *names = [ASConfigurationTests names];
- for (NSInteger i = 0; i < names.count; i++) {
- XCTAssertEqualObjects(@[names[i]], ASExperimentalFeaturesGetNames(features[i]));
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASControlNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASControlNodeTests.mm
deleted file mode 100644
index e1c0150a0d..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASControlNodeTests.mm
+++ /dev/null
@@ -1,225 +0,0 @@
-//
-// ASControlNodeTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-
-#define ACTION @selector(action)
-#define ACTION_SENDER @selector(action:)
-#define ACTION_SENDER_EVENT @selector(action:event:)
-#define EVENT ASControlNodeEventTouchUpInside
-
-@interface ReceiverController : UIViewController
-@property (nonatomic) NSInteger hits;
-@end
-@implementation ReceiverController
-@end
-
-@interface ASActionController : ReceiverController
-@end
-@implementation ASActionController
-- (void)action { self.hits++; }
-- (void)firstAction { }
-- (void)secondAction { }
-- (void)thirdAction { }
-@end
-
-@interface ASActionSenderController : ReceiverController
-@end
-@implementation ASActionSenderController
-- (void)action:(id)sender { self.hits++; }
-@end
-
-@interface ASActionSenderEventController : ReceiverController
-@end
-@implementation ASActionSenderEventController
-- (void)action:(id)sender event:(UIEvent *)event { self.hits++; }
-@end
-
-@interface ASGestureController : ReceiverController
-@end
-@implementation ASGestureController
-- (void)onGesture:(UIGestureRecognizer *)recognizer { self.hits++; }
-- (void)action:(id)sender { self.hits++; }
-@end
-
-@interface ASControlNodeTests : XCTestCase
-
-@end
-
-@implementation ASControlNodeTests
-
-- (void)testActionWithoutParameters {
- ASActionController *controller = [[ASActionController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testActionAndSender {
- ASActionSenderController *controller = [[ASActionSenderController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testActionAndSenderAndEvent {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testActionWithoutTarget {
- ASActionController *controller = [[ASActionController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testActionAndSenderWithoutTarget {
- ASActionSenderController *controller = [[ASActionSenderController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION_SENDER forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testActionAndSenderAndEventWithoutTarget {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testRemoveWithoutTargetRemovesTargetlessAction {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node removeTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events");
-}
-
-- (void)testRemoveWithTarget {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node removeTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events");
-}
-
-- (void)testRemoveWithTargetRemovesAction {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node removeTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events");
-}
-
-- (void)testRemoveWithoutTargetRemovesTargetedAction {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node removeTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 0, @"Controller did not receive exactly zero action events");
-}
-
-- (void)testDuplicateEntriesWithoutTarget {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 1, @"Controller did not receive exactly one action event");
-}
-
-- (void)testDuplicateEntriesWithTarget {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 1, @"Controller did not receive exactly one action event");
-}
-
-- (void)testDuplicateEntriesWithAndWithoutTarget {
- ASActionSenderEventController *controller = [[ASActionSenderEventController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [node addTarget:nil action:ACTION_SENDER_EVENT forControlEvents:EVENT];
- [controller.view addSubview:node.view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssertEqual(controller.hits, 2, @"Controller did not receive exactly two action events");
-}
-
-- (void)testDeeperHierarchyWithoutTarget {
- ASActionController *controller = [[ASActionController alloc] init];
- UIView *view = [[UIView alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:nil action:ACTION forControlEvents:EVENT];
- [view addSubview:node.view];
- [controller.view addSubview:view];
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the action event");
-}
-
-- (void)testTouchesWorkWithGestures {
- ASGestureController *controller = [[ASGestureController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:@selector(action:) forControlEvents:ASControlNodeEventTouchUpInside];
- [node.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:controller action:@selector(onGesture:)]];
- [controller.view addSubnode:node];
-
- [node sendActionsForControlEvents:EVENT withEvent:nil];
- XCTAssert(controller.hits == 1, @"Controller did not receive the tap event");
-}
-
-- (void)testActionsAreCalledInTheSameOrderAsTheyWereAdded {
- ASActionController *controller = [[ASActionController alloc] init];
- ASControlNode *node = [[ASControlNode alloc] init];
- [node addTarget:controller action:@selector(firstAction) forControlEvents:ASControlNodeEventTouchUpInside];
- [node addTarget:controller action:@selector(secondAction) forControlEvents:ASControlNodeEventTouchUpInside];
- [node addTarget:controller action:@selector(thirdAction) forControlEvents:ASControlNodeEventTouchUpInside];
- [controller.view addSubnode:node];
-
- id controllerMock = [OCMockObject partialMockForObject:controller];
- [controllerMock setExpectationOrderMatters:YES];
- [[controllerMock expect] firstAction];
- [[controllerMock expect] secondAction];
- [[controllerMock expect] thirdAction];
-
- [node sendActionsForControlEvents:ASControlNodeEventTouchUpInside withEvent:nil];
-
- [controllerMock verify];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASCornerLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASCornerLayoutSpecSnapshotTests.mm
deleted file mode 100644
index 2c496cd595..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASCornerLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,215 +0,0 @@
-//
-// ASCornerLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-#import
-#import
-
-typedef NS_ENUM(NSInteger, ASCornerLayoutSpecSnapshotTestsOffsetOption) {
- ASCornerLayoutSpecSnapshotTestsOffsetOptionCenter,
- ASCornerLayoutSpecSnapshotTestsOffsetOptionInner,
- ASCornerLayoutSpecSnapshotTestsOffsetOptionOuter,
-};
-
-
-@interface ASCornerLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-
-@property (nonatomic, copy) UIColor *boxColor;
-@property (nonatomic, copy) UIColor *baseColor;
-@property (nonatomic, copy) UIColor *cornerColor;
-@property (nonatomic, copy) UIColor *contextColor;
-
-@property (nonatomic) CGSize baseSize;
-@property (nonatomic) CGSize cornerSize;
-@property (nonatomic) CGSize contextSize;
-
-@property (nonatomic) ASSizeRange contextSizeRange;
-
-@end
-
-
-@implementation ASCornerLayoutSpecSnapshotTests
-
-- (void)setUp
-{
- [super setUp];
-
- self.recordMode = NO;
-
- _boxColor = [UIColor greenColor];
- _baseColor = [UIColor blueColor];
- _cornerColor = [UIColor orangeColor];
- _contextColor = [UIColor lightGrayColor];
-
- _baseSize = CGSizeMake(60, 60);
- _cornerSize = CGSizeMake(20, 20);
- _contextSize = CGSizeMake(120, 120);
-
- _contextSizeRange = ASSizeRangeMake(CGSizeZero, _contextSize);
-}
-
-- (void)testCornerSpecForAllLocations
-{
- ASCornerLayoutSpecSnapshotTestsOffsetOption center = ASCornerLayoutSpecSnapshotTestsOffsetOptionCenter;
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:center wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:center wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:center wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:center wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:center wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:center wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:center wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:center wrapsCorner:YES];
-}
-
-- (void)testCornerSpecForAllLocationsWithInnerOffset
-{
- ASCornerLayoutSpecSnapshotTestsOffsetOption inner = ASCornerLayoutSpecSnapshotTestsOffsetOptionInner;
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:inner wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:inner wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:inner wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:inner wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:inner wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:inner wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:inner wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:inner wrapsCorner:YES];
-}
-
-- (void)testCornerSpecForAllLocationsWithOuterOffset
-{
- ASCornerLayoutSpecSnapshotTestsOffsetOption outer = ASCornerLayoutSpecSnapshotTestsOffsetOptionOuter;
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:outer wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopLeft offsetOption:outer wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:outer wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationTopRight offsetOption:outer wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:outer wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomLeft offsetOption:outer wrapsCorner:YES];
-
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:outer wrapsCorner:NO];
- [self testCornerSpecWithLocation:ASCornerLayoutLocationBottomRight offsetOption:outer wrapsCorner:YES];
-}
-
-- (void)testCornerSpecWithLocation:(ASCornerLayoutLocation)location
- offsetOption:(ASCornerLayoutSpecSnapshotTestsOffsetOption)offsetOption
- wrapsCorner:(BOOL)wrapsCorner
-{
- ASDisplayNode *baseNode = ASDisplayNodeWithBackgroundColor(_baseColor, _baseSize);
- ASDisplayNode *cornerNode = ASDisplayNodeWithBackgroundColor(_cornerColor, _cornerSize);
- ASDisplayNode *debugBoxNode = ASDisplayNodeWithBackgroundColor(_boxColor);
-
- baseNode.style.layoutPosition = CGPointMake((_contextSize.width - _baseSize.width) / 2,
- (_contextSize.height - _baseSize.height) / 2);
-
- ASCornerLayoutSpec *cornerSpec = [ASCornerLayoutSpec cornerLayoutSpecWithChild:baseNode
- corner:cornerNode
- location:location];
-
- CGPoint delta = (CGPoint){ _cornerSize.width / 2, _cornerSize.height / 2 };
- cornerSpec.offset = [self offsetForOption:offsetOption location:location delta:delta];
- cornerSpec.wrapsCorner = wrapsCorner;
-
- ASBackgroundLayoutSpec *backgroundSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:cornerSpec
- background:debugBoxNode];
-
- [self testLayoutSpec:backgroundSpec
- sizeRange:_contextSizeRange
- subnodes:@[debugBoxNode, baseNode, cornerNode]
- identifier:[self suffixWithLocation:location option:offsetOption wrapsCorner:wrapsCorner]];
-}
-
-- (CGPoint)offsetForOption:(ASCornerLayoutSpecSnapshotTestsOffsetOption)option
- location:(ASCornerLayoutLocation)location
- delta:(CGPoint)delta
-{
- CGFloat x = delta.x;
- CGFloat y = delta.y;
-
- switch (option) {
-
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionCenter:
- return CGPointZero;
-
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionInner:
-
- switch (location) {
- case ASCornerLayoutLocationTopLeft: return (CGPoint){ x, y };
- case ASCornerLayoutLocationTopRight: return (CGPoint){ -x, y };
- case ASCornerLayoutLocationBottomLeft: return (CGPoint){ x, -y };
- case ASCornerLayoutLocationBottomRight: return (CGPoint){ -x, -y };
- }
-
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionOuter:
-
- switch (location) {
- case ASCornerLayoutLocationTopLeft: return (CGPoint){ -x, -y };
- case ASCornerLayoutLocationTopRight: return (CGPoint){ x, -y };
- case ASCornerLayoutLocationBottomLeft: return (CGPoint){ -x, y };
- case ASCornerLayoutLocationBottomRight: return (CGPoint){ x, y };
- }
-
- }
-
-}
-
-- (NSString *)suffixWithLocation:(ASCornerLayoutLocation)location
- option:(ASCornerLayoutSpecSnapshotTestsOffsetOption)option
- wrapsCorner:(BOOL)wrapsCorner
-{
- NSMutableString *desc = [NSMutableString string];
-
- switch (location) {
- case ASCornerLayoutLocationTopLeft:
- [desc appendString:@"topLeft"];
- break;
- case ASCornerLayoutLocationTopRight:
- [desc appendString:@"topRight"];
- break;
- case ASCornerLayoutLocationBottomLeft:
- [desc appendString:@"bottomLeft"];
- break;
- case ASCornerLayoutLocationBottomRight:
- [desc appendString:@"bottomRight"];
- break;
- }
-
- [desc appendString:@"_"];
-
- switch (option) {
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionCenter:
- [desc appendString:@"center"];
- break;
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionInner:
- [desc appendString:@"inner"];
- break;
- case ASCornerLayoutSpecSnapshotTestsOffsetOptionOuter:
- [desc appendString:@"outer"];
- break;
- }
-
- [desc appendString:@"_"];
-
- if (wrapsCorner) {
- [desc appendString:@"fullSize"];
- } else {
- [desc appendString:@"childSize"];
- }
-
- return desc.copy;
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDimensionTests.mm b/submodules/AsyncDisplayKit/Tests/ASDimensionTests.mm
deleted file mode 100644
index c3e30ae63c..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDimensionTests.mm
+++ /dev/null
@@ -1,106 +0,0 @@
-//
-// ASDimensionTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-#import "ASXCTExtensions.h"
-
-
-@interface ASDimensionTests : XCTestCase
-@end
-
-@implementation ASDimensionTests
-
-- (void)testCreatingDimensionUnitAutos
-{
- XCTAssertNoThrow(ASDimensionMake(ASDimensionUnitAuto, 0));
- XCTAssertThrows(ASDimensionMake(ASDimensionUnitAuto, 100));
- ASXCTAssertEqualDimensions(ASDimensionAuto, ASDimensionMake(@""));
- ASXCTAssertEqualDimensions(ASDimensionAuto, ASDimensionMake(@"auto"));
-}
-
-- (void)testCreatingDimensionUnitFraction
-{
- XCTAssertNoThrow(ASDimensionMake(ASDimensionUnitFraction, 0.5));
- ASXCTAssertEqualDimensions(ASDimensionMake(ASDimensionUnitFraction, 0.5), ASDimensionMake(@"50%"));
-}
-
-- (void)testCreatingDimensionUnitPoints
-{
- XCTAssertNoThrow(ASDimensionMake(ASDimensionUnitPoints, 100));
- ASXCTAssertEqualDimensions(ASDimensionMake(ASDimensionUnitPoints, 100), ASDimensionMake(@"100pt"));
-}
-
-- (void)testIntersectingOverlappingSizeRangesReturnsTheirIntersection
-{
- // range: |---------|
- // other: |----------|
- // result: |----|
-
- ASSizeRange range = {{0,0}, {10,10}};
- ASSizeRange other = {{7,7}, {15,15}};
- ASSizeRange result = ASSizeRangeIntersect(range, other);
- ASSizeRange expected = {{7,7}, {10,10}};
- XCTAssertTrue(ASSizeRangeEqualToSizeRange(result, expected), @"Expected %@ but got %@", NSStringFromASSizeRange(expected), NSStringFromASSizeRange(result));
-}
-
-- (void)testIntersectingSizeRangeWithRangeThatContainsItReturnsSameRange
-{
- // range: |-----|
- // other: |---------|
- // result: |-----|
-
- ASSizeRange range = {{2,2}, {8,8}};
- ASSizeRange other = {{0,0}, {10,10}};
- ASSizeRange result = ASSizeRangeIntersect(range, other);
- ASSizeRange expected = {{2,2}, {8,8}};
- XCTAssertTrue(ASSizeRangeEqualToSizeRange(result, expected), @"Expected %@ but got %@", NSStringFromASSizeRange(expected), NSStringFromASSizeRange(result));
-}
-
-- (void)testIntersectingSizeRangeWithRangeContainedWithinItReturnsContainedRange
-{
- // range: |---------|
- // other: |-----|
- // result: |-----|
-
- ASSizeRange range = {{0,0}, {10,10}};
- ASSizeRange other = {{2,2}, {8,8}};
- ASSizeRange result = ASSizeRangeIntersect(range, other);
- ASSizeRange expected = {{2,2}, {8,8}};
- XCTAssertTrue(ASSizeRangeEqualToSizeRange(result, expected), @"Expected %@ but got %@", NSStringFromASSizeRange(expected), NSStringFromASSizeRange(result));
-}
-
-- (void)testIntersectingSizeRangeWithNonOverlappingRangeToRightReturnsSinglePointNearestOtherRange
-{
- // range: |-----|
- // other: |---|
- // result: *
-
- ASSizeRange range = {{0,0}, {5,5}};
- ASSizeRange other = {{10,10}, {15,15}};
- ASSizeRange result = ASSizeRangeIntersect(range, other);
- ASSizeRange expected = {{5,5}, {5,5}};
- XCTAssertTrue(ASSizeRangeEqualToSizeRange(result, expected), @"Expected %@ but got %@", NSStringFromASSizeRange(expected), NSStringFromASSizeRange(result));
-}
-
-- (void)testIntersectingSizeRangeWithNonOverlappingRangeToLeftReturnsSinglePointNearestOtherRange
-{
- // range: |---|
- // other: |-----|
- // result: *
-
- ASSizeRange range = {{10,10}, {15,15}};
- ASSizeRange other = {{0,0}, {5,5}};
- ASSizeRange result = ASSizeRangeIntersect(range, other);
- ASSizeRange expected = {{10,10}, {10,10}};
- XCTAssertTrue(ASSizeRangeEqualToSizeRange(result, expected), @"Expected %@ but got %@", NSStringFromASSizeRange(expected), NSStringFromASSizeRange(result));
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDispatchTests.mm b/submodules/AsyncDisplayKit/Tests/ASDispatchTests.mm
deleted file mode 100644
index a90bce7ed8..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDispatchTests.mm
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// ASDispatchTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-@interface ASDispatchTests : XCTestCase
-
-@end
-
-@implementation ASDispatchTests
-
-- (void)testDispatchApply
-{
- dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- NSInteger expectedThreadCount = [NSProcessInfo processInfo].activeProcessorCount * 2;
- NSLock *lock = [NSLock new];
- NSMutableSet *threads = [NSMutableSet set];
- NSMutableIndexSet *indices = [NSMutableIndexSet indexSet];
-
- size_t const iterations = 1E5;
- ASDispatchApply(iterations, q, 0, ^(size_t i) {
- [lock lock];
- [threads addObject:[NSThread currentThread]];
- XCTAssertFalse([indices containsIndex:i]);
- [indices addIndex:i];
- [lock unlock];
- });
- XCTAssertLessThanOrEqual(threads.count, expectedThreadCount);
- XCTAssertEqualObjects(indices, [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, iterations)]);
-}
-
-- (void)testDispatchAsync
-{
- dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- NSInteger expectedThreadCount = [NSProcessInfo processInfo].activeProcessorCount * 2;
- NSLock *lock = [NSLock new];
- NSMutableSet *threads = [NSMutableSet set];
- NSMutableIndexSet *indices = [NSMutableIndexSet indexSet];
- XCTestExpectation *expectation = [self expectationWithDescription:@"Executed all blocks"];
-
- size_t const iterations = 1E5;
- ASDispatchAsync(iterations, q, 0, ^(size_t i) {
- [lock lock];
- [threads addObject:[NSThread currentThread]];
- XCTAssertFalse([indices containsIndex:i]);
- [indices addIndex:i];
- if (indices.count == iterations) {
- [expectation fulfill];
- }
- [lock unlock];
- });
- [self waitForExpectationsWithTimeout:10 handler:nil];
- XCTAssertLessThanOrEqual(threads.count, expectedThreadCount);
- XCTAssertEqualObjects(indices, [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, iterations)]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayLayerTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayLayerTests.mm
deleted file mode 100644
index 2e03eb6da2..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayLayerTests.mm
+++ /dev/null
@@ -1,598 +0,0 @@
-//
-// ASDisplayLayerTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-#import
-
-#import
-
-#import "ASDisplayNodeTestsHelper.h"
-
-static UIImage *bogusImage() {
- static UIImage *bogusImage = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
-
- UIGraphicsBeginImageContext(CGSizeMake(10, 10));
-
- bogusImage = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
-
- });
-
- return bogusImage;
-}
-
-@interface _ASDisplayLayerTestContainerLayer : CALayer
-@property (nonatomic, readonly) NSUInteger didCompleteTransactionCount;
-@end
-
-@implementation _ASDisplayLayerTestContainerLayer
-
-- (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction
-{
- _didCompleteTransactionCount++;
-}
-
-@end
-
-
-@interface ASDisplayNode (HackForTests)
-- (id)initWithViewClass:(Class)viewClass;
-- (id)initWithLayerClass:(Class)layerClass;
-@end
-
-
-@interface _ASDisplayLayerTestLayer : _ASDisplayLayer
-{
- BOOL _isInCancelAsyncDisplay;
- BOOL _isInDisplay;
-}
-@property (nonatomic, readonly) NSUInteger displayCount;
-@property (nonatomic, readonly) NSUInteger drawInContextCount;
-@property (nonatomic, readonly) NSUInteger setContentsAsyncCount;
-@property (nonatomic, readonly) NSUInteger setContentsSyncCount;
-@property (nonatomic, copy, readonly) NSString *setContentsCounts;
-- (BOOL)checkSetContentsCountsWithSyncCount:(NSUInteger)syncCount asyncCount:(NSUInteger)asyncCount;
-@end
-
-@implementation _ASDisplayLayerTestLayer
-
-- (NSString *)setContentsCounts
-{
- return [NSString stringWithFormat:@"syncCount:%tu, asyncCount:%tu", _setContentsSyncCount, _setContentsAsyncCount];
-}
-
-- (BOOL)checkSetContentsCountsWithSyncCount:(NSUInteger)syncCount asyncCount:(NSUInteger)asyncCount
-{
- return ((syncCount == _setContentsSyncCount) &&
- (asyncCount == _setContentsAsyncCount));
-}
-
-- (void)setContents:(id)contents
-{
- [super setContents:contents];
-
- if (self.displaysAsynchronously) {
- if (_isInDisplay) {
- [NSException raise:NSInvalidArgumentException format:@"There is no placeholder logic in _ASDisplayLayer, unknown caller for setContents:"];
- } else if (!_isInCancelAsyncDisplay) {
- _setContentsAsyncCount++;
- }
- } else {
- _setContentsSyncCount++;
- }
-}
-
-- (void)display
-{
- _isInDisplay = YES;
- [super display];
- _isInDisplay = NO;
- _displayCount++;
-}
-
-- (void)cancelAsyncDisplay
-{
- _isInCancelAsyncDisplay = YES;
- [super cancelAsyncDisplay];
- _isInCancelAsyncDisplay = NO;
-}
-
-// This should never get called. This just records if it is.
-- (void)drawInContext:(CGContextRef)context
-{
- [super drawInContext:context];
- _drawInContextCount++;
-}
-
-@end
-
-typedef NS_ENUM(NSUInteger, _ASDisplayLayerTestDelegateMode)
-{
- _ASDisplayLayerTestDelegateModeNone = 0,
- _ASDisplayLayerTestDelegateModeDrawParameters = 1 << 0,
- _ASDisplayLayerTestDelegateModeWillDisplay = 1 << 1,
- _ASDisplayLayerTestDelegateModeDidDisplay = 1 << 2,
-};
-
-typedef NS_ENUM(NSUInteger, _ASDisplayLayerTestDelegateClassModes) {
- _ASDisplayLayerTestDelegateClassModeNone = 0,
- _ASDisplayLayerTestDelegateClassModeDisplay = 1 << 0,
- _ASDisplayLayerTestDelegateClassModeDrawInContext = 1 << 1,
-};
-
-@interface _ASDisplayLayerTestDelegate : ASDisplayNode <_ASDisplayLayerDelegate>
-
-@property (nonatomic) NSUInteger didDisplayCount;
-@property (nonatomic) NSUInteger drawParametersCount;
-@property (nonatomic) NSUInteger willDisplayCount;
-
-// for _ASDisplayLayerTestDelegateModeClassDisplay
-@property (nonatomic) NSUInteger displayCount;
-@property (nonatomic) UIImage *(^displayLayerBlock)(void);
-
-// for _ASDisplayLayerTestDelegateModeClassDrawInContext
-@property (nonatomic) NSUInteger drawRectCount;
-
-@end
-
-@implementation _ASDisplayLayerTestDelegate {
- _ASDisplayLayerTestDelegateMode _modes;
-}
-
-static _ASDisplayLayerTestDelegateClassModes _class_modes;
-
-+ (void)setClassModes:(_ASDisplayLayerTestDelegateClassModes)classModes
-{
- _class_modes = classModes;
-}
-
-- (id)initWithModes:(_ASDisplayLayerTestDelegateMode)modes
-{
- _modes = modes;
-
- if (!(self = [super initWithLayerClass:[_ASDisplayLayerTestLayer class]]))
- return nil;
-
- return self;
-}
-
-- (void)didDisplayAsyncLayer:(_ASDisplayLayer *)layer
-{
- _didDisplayCount++;
-}
-
-- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
-{
- _drawParametersCount++;
- return self;
-}
-
-- (void)willDisplayAsyncLayer:(_ASDisplayLayer *)layer
-{
- _willDisplayCount++;
-}
-
-- (BOOL)respondsToSelector:(SEL)selector
-{
- if (sel_isEqual(selector, @selector(didDisplayAsyncLayer:))) {
- return (_modes & _ASDisplayLayerTestDelegateModeDidDisplay);
- } else if (sel_isEqual(selector, @selector(drawParametersForAsyncLayer:))) {
- return (_modes & _ASDisplayLayerTestDelegateModeDrawParameters);
- } else if (sel_isEqual(selector, @selector(willDisplayAsyncLayer:))) {
- return (_modes & _ASDisplayLayerTestDelegateModeWillDisplay);
- } else {
- return [super respondsToSelector:selector];
- }
-}
-
-+ (BOOL)respondsToSelector:(SEL)selector
-{
- if (sel_isEqual(selector, @selector(displayWithParameters:isCancelled:))) {
- return _class_modes & _ASDisplayLayerTestDelegateClassModeDisplay;
- } else if (sel_isEqual(selector, @selector(drawRect:withParameters:isCancelled:isRasterizing:))) {
- return _class_modes & _ASDisplayLayerTestDelegateClassModeDrawInContext;
- } else {
- return [super respondsToSelector:selector];
- }
-}
-
-// DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests!
-+ (UIImage *)displayWithParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock
-{
- UIImage *contents = bogusImage();
- if (delegate->_displayLayerBlock != NULL) {
- contents = delegate->_displayLayerBlock();
- }
- delegate->_displayCount++;
- return contents;
-}
-
-// DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests!
-+ (void)drawRect:(CGRect)bounds withParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock isRasterizing:(BOOL)isRasterizing
-{
- __atomic_add_fetch(&delegate->_drawRectCount, 1, __ATOMIC_SEQ_CST);
-}
-
-- (NSUInteger)drawRectCount
-{
- return(__atomic_load_n(&_drawRectCount, __ATOMIC_SEQ_CST));
-}
-
-@end
-
-@interface _ASDisplayLayerTests : XCTestCase
-@end
-
-@implementation _ASDisplayLayerTests
-
-- (void)setUp {
- [super setUp];
- // Force bogusImage() to create+cache its image. This impacts any time-sensitive tests which call the method from
- // within the timed portion of the test. It seems that, in rare cases, this image creation can take a bit too long,
- // causing a test failure.
- bogusImage();
-}
-
-// since we're not running in an application, we need to force this display on layer the hierarchy
-- (void)displayLayerRecursively:(CALayer *)layer
-{
- if (layer.needsDisplay) {
- [layer displayIfNeeded];
- }
- for (CALayer *sublayer in layer.sublayers) {
- [self displayLayerRecursively:sublayer];
- }
-}
-
-- (void)waitForDisplayQueue
-{
- // make sure we don't lock up the tests indefinitely; fail after 1 sec by using an async barrier
- __block BOOL didHitBarrier = NO;
- dispatch_barrier_async([_ASDisplayLayer displayQueue], ^{
- __atomic_store_n(&didHitBarrier, YES, __ATOMIC_SEQ_CST);
- });
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return __atomic_load_n(&didHitBarrier, __ATOMIC_SEQ_CST); }));
-}
-
-- (void)waitForLayer:(_ASDisplayLayerTestLayer *)layer asyncDisplayCount:(NSUInteger)count
-{
- // make sure we don't lock up the tests indefinitely; fail after 1 sec of waiting for the setContents async count to increment
- // NOTE: the layer sets its contents async back on the main queue, so we need to wait for main
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (layer.setContentsAsyncCount == count);
- }));
-}
-
-- (void)waitForAsyncDelegate:(_ASDisplayLayerTestDelegate *)asyncDelegate
-{
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (asyncDelegate.didDisplayCount == 1);
- }));
-}
-
-- (void)checkDelegateDisplay:(BOOL)displaysAsynchronously
-{
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
- _ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
-
- _ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
- layer.displaysAsynchronously = displaysAsynchronously;
-
- if (displaysAsynchronously) {
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- }
- layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
- [layer setNeedsDisplay];
- [layer displayIfNeeded];
-
- if (displaysAsynchronously) {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForDisplayQueue];
- [self waitForAsyncDelegate:asyncDelegate];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
- } else {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
- }
-
- XCTAssertFalse(layer.needsDisplay);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
- XCTAssertEqual(asyncDelegate.displayCount, 1u);
-}
-
-- (void)testDelegateDisplaySync
-{
- [self checkDelegateDisplay:NO];
-}
-
-- (void)testDelegateDisplayAsync
-{
- [self checkDelegateDisplay:YES];
-}
-
-- (void)checkDelegateDrawInContext:(BOOL)displaysAsynchronously
-{
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDrawInContext];
- _ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
-
- _ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
- layer.displaysAsynchronously = displaysAsynchronously;
-
- if (displaysAsynchronously) {
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- }
- layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
- [layer setNeedsDisplay];
- [layer displayIfNeeded];
-
- if (displaysAsynchronously) {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForLayer:layer asyncDisplayCount:1];
- [self waitForAsyncDelegate:asyncDelegate];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
- } else {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
- }
-
- XCTAssertFalse(layer.needsDisplay);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
- XCTAssertEqual(asyncDelegate.displayCount, 0u);
- XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 1u);
-}
-
-- (void)testDelegateDrawInContextSync
-{
- [self checkDelegateDrawInContext:NO];
-}
-
-- (void)testDelegateDrawInContextAsync
-{
- [self checkDelegateDrawInContext:YES];
-}
-
-- (void)checkDelegateDisplayAndDrawInContext:(BOOL)displaysAsynchronously
-{
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModes(_ASDisplayLayerTestDelegateClassModeDisplay | _ASDisplayLayerTestDelegateClassModeDrawInContext)];
- _ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
-
- _ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
- layer.displaysAsynchronously = displaysAsynchronously;
-
- if (displaysAsynchronously) {
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- }
- layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
- [layer setNeedsDisplay];
- [layer displayIfNeeded];
-
- if (displaysAsynchronously) {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForDisplayQueue];
- [self waitForAsyncDelegate:asyncDelegate];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
- } else {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
- }
-
- XCTAssertFalse(layer.needsDisplay);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.didDisplayCount, 1u);
- XCTAssertEqual(asyncDelegate.displayCount, 1u);
- XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
-}
-
-- (void)testDelegateDisplayAndDrawInContextSync
-{
- [self checkDelegateDisplayAndDrawInContext:NO];
-}
-
-- (void)testDelegateDisplayAndDrawInContextAsync
-{
- [self checkDelegateDisplayAndDrawInContext:YES];
-}
-
-- (void)testCancelAsyncDisplay
-{
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
- _ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateModeDidDisplay];
- _ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
-
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
- [layer setNeedsDisplay];
- XCTAssertTrue(layer.needsDisplay);
- [layer displayIfNeeded];
-
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertFalse(layer.needsDisplay);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
-
- [layer cancelAsyncDisplay];
-
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForDisplayQueue];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertEqual(layer.displayCount, 1u);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.didDisplayCount, 0u);
- XCTAssertEqual(asyncDelegate.displayCount, 0u);
- XCTAssertEqual(asyncDelegate.drawParametersCount, 0u);
-}
-
-- (void)DISABLED_testTransaction
-{
- auto delegateModes = _ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters);
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDisplay];
-
- // Setup
- _ASDisplayLayerTestContainerLayer *containerLayer = [[_ASDisplayLayerTestContainerLayer alloc] init];
- containerLayer.asyncdisplaykit_asyncTransactionContainer = YES;
- containerLayer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
-
- _ASDisplayLayerTestDelegate *layer1Delegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:delegateModes];
- _ASDisplayLayerTestLayer *layer1 = (_ASDisplayLayerTestLayer *)layer1Delegate.layer;
- layer1.displaysAsynchronously = YES;
-
- dispatch_semaphore_t displayAsyncLayer1Sema = dispatch_semaphore_create(0);
- layer1Delegate.displayLayerBlock = ^UIImage *{
- dispatch_semaphore_wait(displayAsyncLayer1Sema, DISPATCH_TIME_FOREVER);
- return bogusImage();
- };
- layer1.backgroundColor = [UIColor blackColor].CGColor;
- layer1.frame = CGRectMake(0.0, 0.0, 333.0, 123.0);
- [containerLayer addSublayer:layer1];
-
- _ASDisplayLayerTestDelegate *layer2Delegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:delegateModes];
- _ASDisplayLayerTestLayer *layer2 = (_ASDisplayLayerTestLayer *)layer2Delegate.layer;
- layer2.displaysAsynchronously = YES;
- layer2.backgroundColor = [UIColor blackColor].CGColor;
- layer2.frame = CGRectMake(0.0, 50.0, 97.0, 50.0);
- [containerLayer addSublayer:layer2];
-
- dispatch_suspend([_ASDisplayLayer displayQueue]);
-
- // display below if needed
- [layer1 setNeedsDisplay];
- [layer2 setNeedsDisplay];
- [containerLayer setNeedsDisplay];
- [self displayLayerRecursively:containerLayer];
-
- // check state before running displayQueue
- XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer1.setContentsCounts);
- XCTAssertEqual(layer1.displayCount, 1u);
- XCTAssertEqual(layer1Delegate.displayCount, 0u);
- XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer2.setContentsCounts);
- XCTAssertEqual(layer2.displayCount, 1u);
- XCTAssertEqual(layer1Delegate.displayCount, 0u);
- XCTAssertEqual(containerLayer.didCompleteTransactionCount, 0u);
-
- // run displayQueue until async display for layer2 has been run
- dispatch_resume([_ASDisplayLayer displayQueue]);
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (layer2Delegate.displayCount == 1);
- }));
-
- // check layer1 has not had async display run
- XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer1.setContentsCounts);
- XCTAssertEqual(layer1.displayCount, 1u);
- XCTAssertEqual(layer1Delegate.displayCount, 0u);
- // check layer2 has had async display run
- XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer2.setContentsCounts);
- XCTAssertEqual(layer2.displayCount, 1u);
- XCTAssertEqual(layer2Delegate.displayCount, 1u);
- XCTAssertEqual(containerLayer.didCompleteTransactionCount, 0u);
-
-
- // allow layer1 to complete display
- dispatch_semaphore_signal(displayAsyncLayer1Sema);
- [self waitForLayer:layer1 asyncDisplayCount:1];
-
- // check that both layers have completed display
- XCTAssertTrue([layer1 checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer1.setContentsCounts);
- XCTAssertEqual(layer1.displayCount, 1u);
- XCTAssertEqual(layer1Delegate.displayCount, 1u);
- XCTAssertTrue([layer2 checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer2.setContentsCounts);
- XCTAssertEqual(layer2.displayCount, 1u);
- XCTAssertEqual(layer2Delegate.displayCount, 1u);
-
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (containerLayer.didCompleteTransactionCount == 1);
- }));
-}
-
-- (void)checkSuspendResume:(BOOL)displaysAsynchronously
-{
- [_ASDisplayLayerTestDelegate setClassModes:_ASDisplayLayerTestDelegateClassModeDrawInContext];
- _ASDisplayLayerTestDelegate *asyncDelegate = [[_ASDisplayLayerTestDelegate alloc] initWithModes:_ASDisplayLayerTestDelegateMode(_ASDisplayLayerTestDelegateModeDidDisplay | _ASDisplayLayerTestDelegateModeDrawParameters)];
-
- _ASDisplayLayerTestLayer *layer = (_ASDisplayLayerTestLayer *)asyncDelegate.layer;
- layer.displaysAsynchronously = displaysAsynchronously;
- layer.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
-
- if (displaysAsynchronously) {
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- }
-
- // Layer shouldn't display because display is suspended
- layer.displaySuspended = YES;
- [layer setNeedsDisplay];
- [layer displayIfNeeded];
- XCTAssertEqual(layer.displayCount, 0u, @"Should not have displayed because display is suspended, thus -setNeedsDisplay is a no-op");
- XCTAssertFalse(layer.needsDisplay, @"Should not need display");
- if (displaysAsynchronously) {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForDisplayQueue];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- } else {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- }
- XCTAssertFalse(layer.needsDisplay);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
-
- // Layer should display because display is resumed
- if (displaysAsynchronously) {
- dispatch_suspend([_ASDisplayLayer displayQueue]);
- }
- layer.displaySuspended = NO;
- XCTAssertTrue(layer.needsDisplay);
- [layer displayIfNeeded];
- XCTAssertEqual(layer.displayCount, 1u);
- if (displaysAsynchronously) {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:0], @"%@", layer.setContentsCounts);
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 0u);
- dispatch_resume([_ASDisplayLayer displayQueue]);
- [self waitForLayer:layer asyncDisplayCount:1];
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:0 asyncCount:1], @"%@", layer.setContentsCounts);
- } else {
- XCTAssertTrue([layer checkSetContentsCountsWithSyncCount:1 asyncCount:0], @"%@", layer.setContentsCounts);
- }
- XCTAssertEqual(layer.drawInContextCount, 0u);
- XCTAssertEqual(asyncDelegate.drawParametersCount, 1u);
- XCTAssertEqual(asyncDelegate.drawRectCount, 1u);
- XCTAssertFalse(layer.needsDisplay);
-}
-
-- (void)testSuspendResumeAsync
-{
- [self checkSuspendResume:YES];
-}
-
-- (void)testSuspendResumeSync
-{
- [self checkSuspendResume:NO];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeAppearanceTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeAppearanceTests.mm
deleted file mode 100644
index 515bcf7cfc..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeAppearanceTests.mm
+++ /dev/null
@@ -1,417 +0,0 @@
-//
-// ASDisplayNodeAppearanceTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-
-#import
-
-#import
-#import
-#import
-#import
-
-// helper functions
-IMP class_replaceMethodWithBlock(Class theClass, SEL originalSelector, id block);
-IMP class_replaceMethodWithBlock(Class theClass, SEL originalSelector, id block)
-{
- IMP newImplementation = imp_implementationWithBlock(block);
- Method method = class_getInstanceMethod(theClass, originalSelector);
- return class_replaceMethod(theClass, originalSelector, newImplementation, method_getTypeEncoding(method));
-}
-
-static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(Class theClass, SEL originalSelector, void (^block)(id))
-{
- __block IMP originalImp = NULL;
- void (^blockActualSwizzle)(id) = ^(id swizzedSelf){
- block(swizzedSelf);
- ((void(*)(id, SEL))originalImp)(swizzedSelf, originalSelector);
- };
- originalImp = class_replaceMethodWithBlock(theClass, originalSelector, blockActualSwizzle);
- void (^cleanupBlock)(void) = ^{
- // restore original method
- Method method = class_getInstanceMethod(theClass, originalSelector);
- class_replaceMethod(theClass, originalSelector, originalImp, method_getTypeEncoding(method));
- };
- return cleanupBlock;
-};
-
-@interface ASDisplayNode (PrivateStuffSoWeDontPullInCPPInternalH)
-- (BOOL)__visibilityNotificationsDisabled;
-- (BOOL)__selfOrParentHasVisibilityNotificationsDisabled;
-- (id)initWithViewClass:(Class)viewClass;
-- (id)initWithLayerClass:(Class)layerClass;
-@end
-
-@interface ASDisplayNodeAppearanceTests : XCTestCase
-@end
-
-// Conveniences for making nodes named a certain way
-#define DeclareNodeNamed(n) ASDisplayNode *n = [[ASDisplayNode alloc] init]; n.debugName = @#n
-#define DeclareViewNamed(v) \
- ASDisplayNode *node_##v = [[ASDisplayNode alloc] init]; \
- node_##v.debugName = @#v; \
- UIView *v = node_##v.view;
-
-@implementation ASDisplayNodeAppearanceTests
-{
- _ASDisplayView *_view;
-
- NSMutableArray *_swizzleCleanupBlocks;
-
- NSCountedSet *_willEnterHierarchyCounts;
- NSCountedSet *_didExitHierarchyCounts;
-
-}
-
-- (void)setUp
-{
- [super setUp];
-
- _swizzleCleanupBlocks = [[NSMutableArray alloc] init];
-
- // Using this instead of mocks. Count # of times method called
- _willEnterHierarchyCounts = [[NSCountedSet alloc] init];
- _didExitHierarchyCounts = [[NSCountedSet alloc] init];
-
- dispatch_block_t cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(willEnterHierarchy), ^(id blockSelf){
- [_willEnterHierarchyCounts addObject:blockSelf];
- });
- [_swizzleCleanupBlocks addObject:cleanupBlock];
- cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(didExitHierarchy), ^(id blockSelf){
- [_didExitHierarchyCounts addObject:blockSelf];
- });
- [_swizzleCleanupBlocks addObject:cleanupBlock];
-}
-
-- (void)tearDown
-{
- [super tearDown];
-
- for(dispatch_block_t cleanupBlock in _swizzleCleanupBlocks) {
- cleanupBlock();
- }
- _swizzleCleanupBlocks = nil;
- _willEnterHierarchyCounts = nil;
- _didExitHierarchyCounts = nil;
-}
-
-- (void)testAppearanceMethodsCalledWithRootNodeInWindowLayer
-{
- [self checkAppearanceMethodsCalledWithRootNodeInWindowLayerBacked:YES];
-}
-
-- (void)testAppearanceMethodsCalledWithRootNodeInWindowView
-{
- [self checkAppearanceMethodsCalledWithRootNodeInWindowLayerBacked:NO];
-}
-
-- (void)checkAppearanceMethodsCalledWithRootNodeInWindowLayerBacked:(BOOL)isLayerBacked
-{
- // ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it.
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
-
- DeclareNodeNamed(n);
- DeclareViewNamed(superview);
-
- n.layerBacked = isLayerBacked;
-
- if (isLayerBacked) {
- [superview.layer addSublayer:n.layer];
- } else {
- [superview addSubview:n.view];
- }
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:n], 0u, @"willEnterHierarchy erroneously called");
- XCTAssertEqual([_didExitHierarchyCounts countForObject:n], 0u, @"didExitHierarchy erroneously called");
-
- [window addSubview:superview];
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:n], 1u, @"willEnterHierarchy not called when node's view added to hierarchy");
- XCTAssertEqual([_didExitHierarchyCounts countForObject:n], 0u, @"didExitHierarchy erroneously called");
-
- XCTAssertTrue(n.inHierarchy, @"Node should be visible");
-
- if (isLayerBacked) {
- [n.layer removeFromSuperlayer];
- } else {
- [n.view removeFromSuperview];
- }
-
- XCTAssertFalse(n.inHierarchy, @"Node should be not visible");
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:n], 1u, @"willEnterHierarchy not called when node's view added to hierarchy");
- XCTAssertEqual([_didExitHierarchyCounts countForObject:n], 1u, @"didExitHierarchy erroneously called");
-}
-
-- (void)checkManualAppearanceViewLoaded:(BOOL)isViewLoaded layerBacked:(BOOL)isLayerBacked
-{
- // ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it.
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
-
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(aa);
- DeclareNodeNamed(ab);
-
- for (ASDisplayNode *n in @[parent, a, b, aa, ab]) {
- n.layerBacked = isLayerBacked;
- if (isViewLoaded)
- [n layer];
- }
-
- [parent addSubnode:a];
-
- XCTAssertFalse(parent.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(a.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(b.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(aa.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(ab.inHierarchy, @"Nothing should be visible");
-
- if (isLayerBacked) {
- [window.layer addSublayer:parent.layer];
- } else {
- [window addSubview:parent.view];
- }
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:parent], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:a], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:b], 0u, @"Should not have appeared yet");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:aa], 0u, @"Should not have appeared yet");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:ab], 0u, @"Should not have appeared yet");
-
- XCTAssertTrue(parent.inHierarchy, @"Should be visible");
- XCTAssertTrue(a.inHierarchy, @"Should be visible");
- XCTAssertFalse(b.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(aa.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(ab.inHierarchy, @"Nothing should be visible");
-
- // Add to an already-visible node should make the node visible
- [parent addSubnode:b];
- [a insertSubnode:aa atIndex:0];
- [a insertSubnode:ab aboveSubnode:aa];
-
- XCTAssertTrue(parent.inHierarchy, @"Should be visible");
- XCTAssertTrue(a.inHierarchy, @"Should be visible");
- XCTAssertTrue(b.inHierarchy, @"Should be visible after adding to visible parent");
- XCTAssertTrue(aa.inHierarchy, @"Nothing should be visible");
- XCTAssertTrue(ab.inHierarchy, @"Nothing should be visible");
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:parent], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:a], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:b], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:aa], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:ab], 1u, @"Should have -willEnterHierarchy called once");
-
- if (isLayerBacked) {
- [parent.layer removeFromSuperlayer];
- } else {
- [parent.view removeFromSuperview];
- }
-
- XCTAssertFalse(parent.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(a.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(b.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(aa.inHierarchy, @"Nothing should be visible");
- XCTAssertFalse(ab.inHierarchy, @"Nothing should be visible");
-}
-
-- (void)testAppearanceMethodsNoLayer
-{
- [self checkManualAppearanceViewLoaded:NO layerBacked:YES];
-}
-
-- (void)testAppearanceMethodsNoView
-{
- [self checkManualAppearanceViewLoaded:NO layerBacked:NO];
-}
-
-- (void)testAppearanceMethodsLayer
-{
- [self checkManualAppearanceViewLoaded:YES layerBacked:YES];
-}
-
-- (void)testAppearanceMethodsView
-{
- [self checkManualAppearanceViewLoaded:YES layerBacked:NO];
-}
-
-- (void)testSynchronousIntermediaryView
-{
- // Parent is a wrapper node for a scrollview
- ASDisplayNode *parentSynchronousNode = [[ASDisplayNode alloc] initWithViewClass:[UIScrollView class]];
- DeclareNodeNamed(layerBackedNode);
- DeclareNodeNamed(viewBackedNode);
-
- layerBackedNode.layerBacked = YES;
-
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
- [parentSynchronousNode addSubnode:layerBackedNode];
- [parentSynchronousNode addSubnode:viewBackedNode];
-
- XCTAssertFalse(parentSynchronousNode.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(layerBackedNode.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(viewBackedNode.inHierarchy, @"Should not yet be visible");
-
- [window addSubview:parentSynchronousNode.view];
-
- // This is a known case that isn't supported
- XCTAssertFalse(parentSynchronousNode.inHierarchy, @"Synchronous views are not currently marked visible");
-
- XCTAssertTrue(layerBackedNode.inHierarchy, @"Synchronous views' subviews should get marked visible");
- XCTAssertTrue(viewBackedNode.inHierarchy, @"Synchronous views' subviews should get marked visible");
-
- // Try moving a node to/from a synchronous node in the window with the node API
- // Setup
- [layerBackedNode removeFromSupernode];
- [viewBackedNode removeFromSupernode];
- XCTAssertFalse(layerBackedNode.inHierarchy, @"aoeu");
- XCTAssertFalse(viewBackedNode.inHierarchy, @"aoeu");
-
- // now move to synchronous node
- [parentSynchronousNode addSubnode:layerBackedNode];
- [parentSynchronousNode insertSubnode:viewBackedNode aboveSubnode:layerBackedNode];
- XCTAssertTrue(layerBackedNode.inHierarchy, @"Synchronous views' subviews should get marked visible");
- XCTAssertTrue(viewBackedNode.inHierarchy, @"Synchronous views' subviews should get marked visible");
-
- [parentSynchronousNode.view removeFromSuperview];
-
- XCTAssertFalse(parentSynchronousNode.inHierarchy, @"Should not have changed");
- XCTAssertFalse(layerBackedNode.inHierarchy, @"Should have been marked invisible when synchronous superview was removed from the window");
- XCTAssertFalse(viewBackedNode.inHierarchy, @"Should have been marked invisible when synchronous superview was removed from the window");
-}
-
-- (void)checkMoveAcrossHierarchyLayerBacked:(BOOL)isLayerBacked useManualCalls:(BOOL)useManualDisable useNodeAPI:(BOOL)useNodeAPI
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
-
- DeclareNodeNamed(parentA);
- DeclareNodeNamed(parentB);
- DeclareNodeNamed(child);
- DeclareNodeNamed(childSubnode);
-
- for (ASDisplayNode *n in @[parentA, parentB, child, childSubnode]) {
- n.layerBacked = isLayerBacked;
- }
-
- [parentA addSubnode:child];
- [child addSubnode:childSubnode];
-
- XCTAssertFalse(parentA.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(parentB.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(child.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(childSubnode.inHierarchy, @"Should not yet be visible");
- XCTAssertFalse(childSubnode.inHierarchy, @"Should not yet be visible");
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:child], 0u, @"Should not have -willEnterHierarchy called");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:childSubnode], 0u, @"Should not have -willEnterHierarchy called");
-
- if (isLayerBacked) {
- [window.layer addSublayer:parentA.layer];
- [window.layer addSublayer:parentB.layer];
- } else {
- [window addSubview:parentA.view];
- [window addSubview:parentB.view];
- }
-
- XCTAssertTrue(parentA.inHierarchy, @"Should be visible after added to window");
- XCTAssertTrue(parentB.inHierarchy, @"Should be visible after added to window");
- XCTAssertTrue(child.inHierarchy, @"Should be visible after parent added to window");
- XCTAssertTrue(childSubnode.inHierarchy, @"Should be visible after parent added to window");
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:child], 1u, @"Should have -willEnterHierarchy called once");
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:childSubnode], 1u, @"Should have -willEnterHierarchy called once");
-
- // Move subnode from A to B
- if (useManualDisable) {
- ASDisplayNodeDisableHierarchyNotifications(child);
- }
- if (!useNodeAPI) {
- [child removeFromSupernode];
- [parentB addSubnode:child];
- } else {
- [parentB addSubnode:child];
- }
- if (useManualDisable) {
- XCTAssertTrue([child __visibilityNotificationsDisabled], @"Should not have re-enabled yet");
- XCTAssertTrue([child __selfOrParentHasVisibilityNotificationsDisabled], @"Should not have re-enabled yet");
- ASDisplayNodeEnableHierarchyNotifications(child);
- }
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:child], 1u, @"Should not have -willEnterHierarchy called when moving child around in hierarchy");
-
- // Move subnode back to A
- if (useManualDisable) {
- ASDisplayNodeDisableHierarchyNotifications(child);
- }
- if (!useNodeAPI) {
- [child removeFromSupernode];
- [parentA insertSubnode:child atIndex:0];
- } else {
- [parentA insertSubnode:child atIndex:0];
- }
- if (useManualDisable) {
- XCTAssertTrue([child __visibilityNotificationsDisabled], @"Should not have re-enabled yet");
- XCTAssertTrue([child __selfOrParentHasVisibilityNotificationsDisabled], @"Should not have re-enabled yet");
- ASDisplayNodeEnableHierarchyNotifications(child);
- }
-
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:child], 1u, @"Should not have -willEnterHierarchy called when moving child around in hierarchy");
-
- // Finally, remove subnode
- [child removeFromSupernode];
-
- XCTAssertEqual([_willEnterHierarchyCounts countForObject:child], 1u, @"Should appear and disappear just once");
-
- // Make sure that we don't leave these unbalanced
- XCTAssertFalse([child __visibilityNotificationsDisabled], @"Unbalanced visibility notifications calls");
- XCTAssertFalse([child __selfOrParentHasVisibilityNotificationsDisabled], @"Should not have re-enabled yet");
-}
-
-- (void)testMoveAcrossHierarchyLayer
-{
- [self checkMoveAcrossHierarchyLayerBacked:YES useManualCalls:NO useNodeAPI:YES];
-}
-
-- (void)testMoveAcrossHierarchyView
-{
- [self checkMoveAcrossHierarchyLayerBacked:NO useManualCalls:NO useNodeAPI:YES];
-}
-
-- (void)testMoveAcrossHierarchyManualLayer
-{
- [self checkMoveAcrossHierarchyLayerBacked:YES useManualCalls:YES useNodeAPI:NO];
-}
-
-- (void)testMoveAcrossHierarchyManualView
-{
- [self checkMoveAcrossHierarchyLayerBacked:NO useManualCalls:YES useNodeAPI:NO];
-}
-
-- (void)testDisableWithNodeAPILayer
-{
- [self checkMoveAcrossHierarchyLayerBacked:YES useManualCalls:YES useNodeAPI:YES];
-}
-
-- (void)testDisableWithNodeAPIView
-{
- [self checkMoveAcrossHierarchyLayerBacked:NO useManualCalls:YES useNodeAPI:YES];
-}
-
-- (void)testPreventManualAppearanceMethods
-{
- DeclareNodeNamed(n);
-
- XCTAssertThrows([n willEnterHierarchy], @"Should not allow manually calling appearance methods.");
- XCTAssertThrows([n didExitHierarchy], @"Should not allow manually calling appearance methods.");
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeExtrasTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeExtrasTests.mm
deleted file mode 100644
index 77d904c2e6..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeExtrasTests.mm
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// ASDisplayNodeExtrasTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-
-@interface ASDisplayNodeExtrasTests : XCTestCase
-
-@end
-
-@interface TestDisplayNode : ASDisplayNode
-@end
-
-@implementation TestDisplayNode
-@end
-
-@implementation ASDisplayNodeExtrasTests
-
-- (void)testShallowFindSubnodesOfSubclass {
- ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
- return [CALayer layer];
- }];
- NSUInteger count = 10;
- NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:count];
- for (NSUInteger nodeIndex = 0; nodeIndex < count; nodeIndex++) {
- TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
- return [CALayer layer];
- }];
- [supernode addSubnode:node];
- [expected addObject:node];
- }
- NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]);
- XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count);
-}
-
-- (void)testDeepFindSubnodesOfSubclass {
- ASDisplayNode *supernode = [[ASDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
- return [CALayer layer];
- }];
-
- const NSUInteger count = 2;
- const NSUInteger levels = 2;
- const NSUInteger capacity = [[self class] capacityForCount:count levels:levels];
- NSMutableArray *expected = [[NSMutableArray alloc] initWithCapacity:capacity];
-
- [[self class] addSubnodesToNode:supernode number:count remainingLevels:levels accumulated:expected];
-
- NSArray *found = ASDisplayNodeFindAllSubnodesOfClass(supernode, [TestDisplayNode class]);
- XCTAssertEqualObjects(found, expected, @"Expecting %lu %@ nodes, found %lu", (unsigned long)count, [TestDisplayNode class], (unsigned long)found.count);
-}
-
-+ (void)addSubnodesToNode:(ASDisplayNode *)supernode number:(NSUInteger)number remainingLevels:(NSUInteger)level accumulated:(inout NSMutableArray *)expected {
- if (level == 0) return;
- for (NSUInteger nodeIndex = 0; nodeIndex < number; nodeIndex++) {
- TestDisplayNode *node = [[TestDisplayNode alloc] initWithLayerBlock:^CALayer * _Nonnull{
- return [CALayer layer];
- }];
- [supernode addSubnode:node];
- [expected addObject:node];
- [self addSubnodesToNode:node number:number remainingLevels:(level - 1) accumulated:expected];
- }
-}
-
-// Graph theory is failing me atm.
-+ (NSUInteger)capacityForCount:(NSUInteger)count levels:(NSUInteger)level {
- if (level == 0) return 0;
- return pow(count, level) + [self capacityForCount:count levels:(level - 1)];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeImplicitHierarchyTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeImplicitHierarchyTests.mm
deleted file mode 100644
index ea41a322b3..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeImplicitHierarchyTests.mm
+++ /dev/null
@@ -1,329 +0,0 @@
-//
-// ASDisplayNodeImplicitHierarchyTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-
-#import "ASDisplayNodeTestsHelper.h"
-
-@interface ASSpecTestDisplayNode : ASDisplayNode
-
-/**
- Simple state identifier to allow control of current spec inside of the layoutSpecBlock
- */
-@property (nonatomic) NSNumber *layoutState;
-
-@end
-
-@implementation ASSpecTestDisplayNode
-
-- (instancetype)init
-{
- self = [super init];
- if (self) {
- _layoutState = @1;
- }
- return self;
-}
-
-@end
-
-@interface ASDisplayNodeImplicitHierarchyTests : XCTestCase
-
-@end
-
-@implementation ASDisplayNodeImplicitHierarchyTests
-
-- (void)testFeatureFlag
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- XCTAssertFalse(node.automaticallyManagesSubnodes);
-
- node.automaticallyManagesSubnodes = YES;
- XCTAssertTrue(node.automaticallyManagesSubnodes);
-}
-
-- (void)testInitialNodeInsertionWithOrdering
-{
- static CGSize kSize = {100, 100};
-
- ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node4 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node5 = [[ASDisplayNode alloc] init];
-
-
- // As we will involve a stack spec we have to give the nodes an intrinsic content size
- node1.style.preferredSize = kSize;
- node2.style.preferredSize = kSize;
- node3.style.preferredSize = kSize;
- node4.style.preferredSize = kSize;
- node5.style.preferredSize = kSize;
-
- ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
- node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
- ASAbsoluteLayoutSpec *absoluteLayout = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node4]];
-
- ASStackLayoutSpec *stack1 = [[ASStackLayoutSpec alloc] init];
- [stack1 setChildren:@[node1, node2]];
-
- ASStackLayoutSpec *stack2 = [[ASStackLayoutSpec alloc] init];
- [stack2 setChildren:@[node3, absoluteLayout]];
-
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[stack1, stack2, node5]];
- };
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)));
- [node.view layoutIfNeeded];
-
- XCTAssertEqual(node.subnodes[0], node1);
- XCTAssertEqual(node.subnodes[1], node2);
- XCTAssertEqual(node.subnodes[2], node3);
- XCTAssertEqual(node.subnodes[3], node4);
- XCTAssertEqual(node.subnodes[4], node5);
-}
-
-- (void)testInitialNodeInsertionWhenEnterPreloadState
-{
- static CGSize kSize = {100, 100};
-
- static NSInteger subnodeCount = 5;
- NSMutableArray *subnodes = [NSMutableArray arrayWithCapacity:subnodeCount];
- for (NSInteger i = 0; i < subnodeCount; i++) {
- ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
- // As we will involve a stack spec we have to give the nodes an intrinsic content size
- subnode.style.preferredSize = kSize;
- [subnodes addObject:subnode];
- }
-
- ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
- [node setHierarchyState:ASHierarchyStateRangeManaged];
- node.automaticallyManagesSubnodes = YES;
- node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
- ASAbsoluteLayoutSpec *absoluteLayout = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[subnodes[3]]];
-
- ASStackLayoutSpec *stack1 = [[ASStackLayoutSpec alloc] init];
- [stack1 setChildren:@[subnodes[0], subnodes[1]]];
-
- ASStackLayoutSpec *stack2 = [[ASStackLayoutSpec alloc] init];
- [stack2 setChildren:@[subnodes[2], absoluteLayout]];
-
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[stack1, stack2, subnodes[4]]];
- };
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)));
- [node recursivelySetInterfaceState:ASInterfaceStatePreload];
-
- ASCATransactionQueueWait(nil);
- // No premature view allocation
- XCTAssertFalse(node.isNodeLoaded);
- // Subnodes should be inserted, laid out and entered preload state
- XCTAssertTrue([subnodes isEqualToArray:node.subnodes]);
- for (NSInteger i = 0; i < subnodeCount; i++) {
- ASDisplayNode *subnode = subnodes[i];
- XCTAssertTrue(CGSizeEqualToSize(kSize, subnode.bounds.size));
- XCTAssertTrue(ASInterfaceStateIncludesPreload(subnode.interfaceState));
- }
-}
-
-- (void)testCalculatedLayoutHierarchyTransitions
-{
- static CGSize kSize = {100, 100};
-
- ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
-
- node1.debugName = @"a";
- node2.debugName = @"b";
- node3.debugName = @"c";
-
- // As we will involve a stack spec we have to give the nodes an intrinsic content size
- node1.style.preferredSize = kSize;
- node2.style.preferredSize = kSize;
- node3.style.preferredSize = kSize;
-
- ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
- node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize){
- ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
- if ([strongNode.layoutState isEqualToNumber:@1]) {
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node1, node2]];
- } else {
- ASStackLayoutSpec *stackLayout = [[ASStackLayoutSpec alloc] init];
- [stackLayout setChildren:@[node3, node2]];
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node1, stackLayout]];
- }
- };
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)));
- [node.view layoutIfNeeded];
- XCTAssertEqual(node.subnodes[0], node1);
- XCTAssertEqual(node.subnodes[1], node2);
-
- node.layoutState = @2;
- [node setNeedsLayout]; // After a state change the layout needs to be invalidated
- [node.view layoutIfNeeded]; // A new layout pass will trigger the hiearchy transition
-
- XCTAssertEqual(node.subnodes[0], node1);
- XCTAssertEqual(node.subnodes[1], node3);
- XCTAssertEqual(node.subnodes[2], node2);
-}
-
-// Disable test for now as we disabled the assertion
-//- (void)testLayoutTransitionWillThrowForManualSubnodeManagement
-//{
-// ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
-// node1.name = @"node1";
-//
-// ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
-// node.automaticallyManagesSubnodes = YES;
-// node.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode *weakNode, ASSizeRange constrainedSize){
-// return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node1]];
-// };
-//
-// XCTAssertNoThrow([node layoutThatFits:ASSizeRangeMake(CGSizeZero)]);
-// XCTAssertThrows([node1 removeFromSupernode]);
-//}
-
-- (void)testLayoutTransitionMeasurementCompletionBlockIsCalledOnMainThread
-{
- const CGSize kSize = CGSizeMake(100, 100);
-
- ASDisplayNode *displayNode = [[ASDisplayNode alloc] init];
- displayNode.style.preferredSize = kSize;
-
- // Trigger explicit view creation to be able to use the Transition API
- [displayNode view];
-
- XCTestExpectation *expectation = [self expectationWithDescription:@"Call measurement completion block on main"];
-
- [displayNode transitionLayoutWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)) animated:YES shouldMeasureAsync:YES measurementCompletion:^{
- XCTAssertTrue(ASDisplayNodeThreadIsMain(), @"Measurement completion block should be called on main thread");
- [expectation fulfill];
- }];
-
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-}
-
-- (void)testMeasurementInBackgroundThreadWithLoadedNode
-{
- const CGSize kNodeSize = CGSizeMake(100, 100);
- ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
-
- ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
- node.style.preferredSize = kNodeSize;
- node.automaticallyManagesSubnodes = YES;
- node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
- ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
- if ([strongNode.layoutState isEqualToNumber:@1]) {
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node1]];
- } else {
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node2]];
- }
- };
-
- // Intentionally trigger view creation
- [node view];
- [node2 view];
-
- XCTestExpectation *expectation = [self expectationWithDescription:@"Fix IHM layout also if one node is already loaded"];
-
- dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-
- // Measurement happens in the background
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
-
- // Dispatch back to the main thread to let the insertion / deletion of subnodes happening
- dispatch_async(dispatch_get_main_queue(), ^{
-
- // Layout on main
- [node setNeedsLayout];
- [node.view layoutIfNeeded];
- XCTAssertEqual(node.subnodes[0], node1);
-
- dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-
- // Change state and measure in the background
- node.layoutState = @2;
- [node setNeedsLayout];
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
-
- // Dispatch back to the main thread to let the insertion / deletion of subnodes happening
- dispatch_async(dispatch_get_main_queue(), ^{
-
- // Layout on main again
- [node.view layoutIfNeeded];
- XCTAssertEqual(node.subnodes[0], node2);
-
- [expectation fulfill];
- });
- });
- });
- });
-
- [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
- if (error) {
- NSLog(@"Timeout Error: %@", error);
- }
- }];
-}
-
-- (void)testTransitionLayoutWithAnimationWithLoadedNodes
-{
- const CGSize kNodeSize = CGSizeMake(100, 100);
- ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
- ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
-
- ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
- node.style.preferredSize = kNodeSize;
- node.layoutSpecBlock = ^(ASDisplayNode *weakNode, ASSizeRange constrainedSize) {
- ASSpecTestDisplayNode *strongNode = (ASSpecTestDisplayNode *)weakNode;
- if ([strongNode.layoutState isEqualToNumber:@1]) {
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node1]];
- } else {
- return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[node2]];
- }
- };
-
- // Intentionally trigger view creation
- [node1 view];
- [node2 view];
-
- XCTestExpectation *expectation = [self expectationWithDescription:@"Fix IHM layout transition also if one node is already loaded"];
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
- [node.view layoutIfNeeded];
- XCTAssertEqual(node.subnodes[0], node1);
-
- node.layoutState = @2;
- [node invalidateCalculatedLayout];
- [node transitionLayoutWithAnimation:YES shouldMeasureAsync:YES measurementCompletion:^{
- // Push this to the next runloop to let async insertion / removing of nodes finished before checking
- dispatch_async(dispatch_get_main_queue(), ^{
- XCTAssertEqual(node.subnodes[0], node2);
- [expectation fulfill];
- });
- }];
-
- [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
- if (error) {
- NSLog(@"Timeout Error: %@", error);
- }
- }];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeLayoutTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeLayoutTests.mm
deleted file mode 100644
index 582e141634..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeLayoutTests.mm
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// ASDisplayNodeLayoutTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASXCTExtensions.h"
-#import
-#import
-#import
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-@interface ASDisplayNodeLayoutTests : XCTestCase
-@end
-
-@implementation ASDisplayNodeLayoutTests
-
-- (void)testMeasureOnLayoutIfNotHappenedBefore
-{
- CGSize nodeSize = CGSizeMake(100, 100);
-
- ASDisplayNode *displayNode = [[ASDisplayNode alloc] init];
- displayNode.style.width = ASDimensionMake(100);
- displayNode.style.height = ASDimensionMake(100);
-
- // Use a button node in here as ASButtonNode uses layoutSpecThatFits:
- ASButtonNode *buttonNode = [ASButtonNode new];
- [displayNode addSubnode:buttonNode];
-
- displayNode.frame = {.size = nodeSize};
- buttonNode.frame = {.size = nodeSize};
-
- ASXCTAssertEqualSizes(displayNode.calculatedSize, CGSizeZero, @"Calculated size before measurement and layout should be 0");
- ASXCTAssertEqualSizes(buttonNode.calculatedSize, CGSizeZero, @"Calculated size before measurement and layout should be 0");
-
- // Trigger view creation and layout pass without a manual -layoutThatFits: call before so the automatic measurement
- // pass will trigger in the layout pass
- [displayNode.view layoutIfNeeded];
-
- ASXCTAssertEqualSizes(displayNode.calculatedSize, nodeSize, @"Automatic measurement pass should have happened in layout pass");
- ASXCTAssertEqualSizes(buttonNode.calculatedSize, nodeSize, @"Automatic measurement pass should have happened in layout pass");
-}
-
-#if DEBUG
-- (void)testNotAllowAddingSubnodesInLayoutSpecThatFits
-{
- ASDisplayNode *displayNode = [ASDisplayNode new];
- ASDisplayNode *someOtherNode = [ASDisplayNode new];
-
- displayNode.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- [node addSubnode:someOtherNode];
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:someOtherNode];
- };
-
- XCTAssertThrows([displayNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))], @"Should throw if subnode was added in layoutSpecThatFits:");
-}
-
-- (void)testNotAllowModifyingSubnodesInLayoutSpecThatFits
-{
- ASDisplayNode *displayNode = [ASDisplayNode new];
- ASDisplayNode *someOtherNode = [ASDisplayNode new];
-
- [displayNode addSubnode:someOtherNode];
-
- displayNode.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- [someOtherNode removeFromSupernode];
- [node addSubnode:[ASDisplayNode new]];
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:someOtherNode];
- };
-
- XCTAssertThrows([displayNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))], @"Should throw if subnodes where modified in layoutSpecThatFits:");
-}
-#endif
-
-- (void)testMeasureOnLayoutIfNotHappenedBeforeNoRemeasureForSameBounds
-{
- CGSize nodeSize = CGSizeMake(100, 100);
-
- ASDisplayNode *displayNode = [ASDisplayNode new];
- displayNode.style.width = ASDimensionMake(nodeSize.width);
- displayNode.style.height = ASDimensionMake(nodeSize.height);
-
- ASButtonNode *buttonNode = [ASButtonNode new];
- [displayNode addSubnode:buttonNode];
-
- __block atomic_int numberOfLayoutSpecThatFitsCalls = ATOMIC_VAR_INIT(0);
- displayNode.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- atomic_fetch_add(&numberOfLayoutSpecThatFitsCalls, 1);
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:buttonNode];
- };
-
- displayNode.frame = {.size = nodeSize};
-
- // Trigger initial layout pass without a measurement pass before
- [displayNode.view layoutIfNeeded];
- XCTAssertEqual(numberOfLayoutSpecThatFitsCalls, 1, @"Should measure during layout if not measured");
-
- [displayNode layoutThatFits:ASSizeRangeMake(nodeSize, nodeSize)];
- XCTAssertEqual(numberOfLayoutSpecThatFitsCalls, 1, @"Should not remeasure with same bounds");
-}
-
-- (void)testThatLayoutWithInvalidSizeCausesException
-{
- ASDisplayNode *displayNode = [[ASDisplayNode alloc] init];
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode *node, ASSizeRange constrainedSize) {
- return [ASWrapperLayoutSpec wrapperWithLayoutElement:displayNode];
- };
-
- XCTAssertThrows([node layoutThatFits:ASSizeRangeMake(CGSizeMake(0, FLT_MAX))]);
-}
-
-- (void)testThatLayoutCreatedWithInvalidSizeCausesException
-{
- ASDisplayNode *displayNode = [[ASDisplayNode alloc] init];
- XCTAssertThrows([ASLayout layoutWithLayoutElement:displayNode size:CGSizeMake(FLT_MAX, FLT_MAX)]);
- XCTAssertThrows([ASLayout layoutWithLayoutElement:displayNode size:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]);
- XCTAssertThrows([ASLayout layoutWithLayoutElement:displayNode size:CGSizeMake(INFINITY, INFINITY)]);
-}
-
-- (void)testThatLayoutElementCreatedInLayoutSpecThatFitsDoNotGetDeallocated
-{
- const CGSize kSize = CGSizeMake(300, 300);
-
- ASDisplayNode *subNode = [[ASDisplayNode alloc] init];
- subNode.automaticallyManagesSubnodes = YES;
- subNode.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- ASTextNode *textNode = [ASTextNode new];
- textNode.attributedText = [[NSAttributedString alloc] initWithString:@"Test Test Test Test Test Test Test Test"];
- ASInsetLayoutSpec *insetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:textNode];
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:insetSpec];
- };
-
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- rootNode.automaticallyManagesSubnodes = YES;
- rootNode.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- ASTextNode *textNode = [ASTextNode new];
- textNode.attributedText = [[NSAttributedString alloc] initWithString:@"Test Test Test Test Test"];
- ASInsetLayoutSpec *insetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:textNode];
-
- return [ASStackLayoutSpec
- stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
- spacing:0.0
- justifyContent:ASStackLayoutJustifyContentStart
- alignItems:ASStackLayoutAlignItemsStretch
- children:@[insetSpec, subNode]];
- };
-
- rootNode.frame = CGRectMake(0, 0, kSize.width, kSize.height);
- [rootNode view];
-
- XCTestExpectation *expectation = [self expectationWithDescription:@"Execute measure and layout pass"];
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-
- [rootNode layoutThatFits:ASSizeRangeMake(kSize)];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- XCTAssertNoThrow([rootNode.view layoutIfNeeded]);
- [expectation fulfill];
- });
- });
-
- [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
- if (error) {
- XCTFail(@"Expectation failed: %@", error);
- }
- }];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeSnapshotTests.mm
deleted file mode 100644
index 489727e3ba..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeSnapshotTests.mm
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// ASDisplayNodeSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASSnapshotTestCase.h"
-#import
-
-@interface ASDisplayNodeSnapshotTests : ASSnapshotTestCase
-
-@end
-
-@implementation ASDisplayNodeSnapshotTests
-
-- (void)testBasicHierarchySnapshotTesting
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.backgroundColor = [UIColor blueColor];
-
- ASTextNode *subnode = [[ASTextNode alloc] init];
- subnode.backgroundColor = [UIColor whiteColor];
-
- subnode.attributedText = [[NSAttributedString alloc] initWithString:@"Hello"];
- node.automaticallyManagesSubnodes = YES;
- node.layoutSpecBlock = ^(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(5, 5, 5, 5) child:subnode];
- };
-
- ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY)));
- ASSnapshotVerifyNode(node, nil);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTests.mm
deleted file mode 100644
index d1e1698413..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTests.mm
+++ /dev/null
@@ -1,2705 +0,0 @@
-//
-// ASDisplayNodeTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-#import
-
-#import "ASXCTExtensions.h"
-#import "ASDisplayNodeTestsHelper.h"
-
-// Conveniences for making nodes named a certain way
-#define DeclareNodeNamed(n) ASDisplayNode *n = [[ASDisplayNode alloc] init]; n.debugName = @#n
-#define DeclareViewNamed(v) \
- ASDisplayNode *node_##v = [[ASDisplayNode alloc] init]; \
- node_##v.debugName = @#v; \
- UIView *v = node_##v.view;
-#define DeclareLayerNamed(l) \
- ASDisplayNode *node_##l = [[ASDisplayNode alloc] init]; \
- node_##l.debugName = @#l; \
- node_##l.layerBacked = YES; \
- CALayer *l = node_##l.layer;
-
-static NSString *orderStringFromSublayers(CALayer *l) {
- return [[[l.sublayers valueForKey:@"asyncdisplaykit_node"] valueForKey:@"debugName"] componentsJoinedByString:@","];
-}
-
-static NSString *orderStringFromSubviews(UIView *v) {
- return [[[v.subviews valueForKey:@"asyncdisplaykit_node"] valueForKey:@"debugName"] componentsJoinedByString:@","];
-}
-
-static NSString *orderStringFromSubnodes(ASDisplayNode *n) {
- return [[n.subnodes valueForKey:@"debugName"] componentsJoinedByString:@","];
-}
-
-// Asserts subnode, subview, sublayer order match what you provide here
-#define XCTAssertNodeSubnodeSubviewSublayerOrder(n, loaded, isLayerBacked, order, description) \
-XCTAssertEqualObjects(orderStringFromSubnodes(n), order, @"Incorrect node order for " description );\
-if (loaded) {\
- if (!isLayerBacked) {\
- XCTAssertEqualObjects(orderStringFromSubviews(n.view), order, @"Incorrect subviews for " description);\
- }\
- XCTAssertEqualObjects(orderStringFromSublayers(n.layer), order, @"Incorrect sublayers for " description);\
-}
-
-#define XCTAssertNodesHaveParent(parent, nodes ...) \
-for (ASDisplayNode *n in @[ nodes ]) {\
- XCTAssertEqualObjects(parent, n.supernode, @"%@ has the wrong parent", n.debugName);\
-}
-
-#define XCTAssertNodesLoaded(nodes ...) \
-for (ASDisplayNode *n in @[ nodes ]) {\
- XCTAssertTrue(n.nodeLoaded, @"%@ should be loaded", n.debugName);\
-}
-
-#define XCTAssertNodesNotLoaded(nodes ...) \
-for (ASDisplayNode *n in @[ nodes ]) {\
- XCTAssertFalse(n.nodeLoaded, @"%@ should not be loaded", n.debugName);\
-}
-
-@interface UIWindow (Testing)
-// UIWindow has this handy method that is not public but great for testing
-- (UIResponder *)firstResponder;
-@end
-
-@interface ASDisplayNode (HackForTests)
-- (id)initWithViewClass:(Class)viewClass;
-- (id)initWithLayerClass:(Class)layerClass;
-- (void)setInterfaceState:(ASInterfaceState)state;
-// FIXME: Importing ASDisplayNodeInternal.h causes a heap of problems.
-- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
-@end
-
-@interface ASTestDisplayNode : ASDisplayNode
-@property (nonatomic) void (^willDeallocBlock)(__unsafe_unretained ASTestDisplayNode *node);
-@property (nonatomic) CGSize(^calculateSizeBlock)(ASTestDisplayNode *node, CGSize size);
-
-@property (nonatomic, nullable) UIGestureRecognizer *gestureRecognizer;
-@property (nonatomic, nullable) id idGestureRecognizer;
-@property (nonatomic, nullable) UIImage *bigImage;
-@property (nonatomic, nullable) NSArray *randomProperty;
-
-@property (nonatomic, nullable) UIGestureRecognizer *gestureRecognizer;
-@property (nonatomic, nullable) id idGestureRecognizer;
-@property (nonatomic, nullable) UIImage *bigImage;
-@property (nonatomic, nullable) NSArray *randomProperty;
-
-@property (nonatomic) BOOL displayRangeStateChangedToYES;
-@property (nonatomic) BOOL displayRangeStateChangedToNO;
-
-@property (nonatomic) BOOL hasPreloaded;
-@property (nonatomic) BOOL preloadStateChangedToYES;
-@property (nonatomic) BOOL preloadStateChangedToNO;
-
-@property (nonatomic) NSUInteger displayWillStartCount;
-@property (nonatomic) NSUInteger didDisplayCount;
-
-@end
-
-@interface ASTestResponderNode : ASTestDisplayNode
-@end
-
-@implementation ASTestDisplayNode
-
-- (void)setInterfaceState:(ASInterfaceState)state
-{
- [super setInterfaceState:state];
- ASCATransactionQueueWait(nil);
-}
-
-- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
-{
- return _calculateSizeBlock ? _calculateSizeBlock(self, constrainedSize) : CGSizeZero;
-}
-
-- (void)didEnterDisplayState
-{
- [super didEnterDisplayState];
- self.displayRangeStateChangedToYES = YES;
-}
-
-- (void)didExitDisplayState
-{
- [super didExitDisplayState];
- self.displayRangeStateChangedToNO = YES;
-}
-
-- (void)didEnterPreloadState
-{
- [super didEnterPreloadState];
- self.preloadStateChangedToYES = YES;
- self.hasPreloaded = YES;
-}
-
-- (void)didExitPreloadState
-{
- [super didExitPreloadState];
- self.preloadStateChangedToNO = YES;
-}
-
-- (void)dealloc
-{
- if (_willDeallocBlock) {
- _willDeallocBlock(self);
- }
-}
-
-- (void)displayDidFinish
-{
- [super displayDidFinish];
- _didDisplayCount++;
-}
-
-- (void)displayWillStartAsynchronously:(BOOL)asynchronously
-{
- [super displayWillStartAsynchronously:asynchronously];
- _displayWillStartCount++;
-}
-
-- (CALayer *__strong (*)[NUM_CLIP_CORNER_LAYERS])clipCornerLayers
-{
- return &self->_clipCornerLayers;
-}
-
-@end
-
-@interface ASSynchronousTestDisplayNodeViaViewClass : ASDisplayNode
-@end
-
-@implementation ASSynchronousTestDisplayNodeViaViewClass
-
-+ (Class)viewClass {
- return [UIView class];
-}
-
-@end
-
-@interface ASSynchronousTestDisplayNodeViaLayerClass : ASDisplayNode
-@end
-
-@implementation ASSynchronousTestDisplayNodeViaLayerClass
-
-+ (Class)layerClass {
- return [CALayer class];
-}
-
-@end
-
-@interface UIDisplayNodeTestView : UIView
-@end
-
-@interface UIResponderNodeTestView : _ASDisplayView
-@property(nonatomic) BOOL testIsFirstResponder;
-@end
-
-@implementation UIDisplayNodeTestView
-@end
-
-@interface ASTestWindow : UIWindow
-@end
-
-@implementation ASTestWindow
-
-- (id)firstResponder {
- return self.subviews.firstObject;
-}
-
-@end
-
-@implementation ASTestResponderNode
-
-+ (Class)viewClass {
- return [UIResponderNodeTestView class];
-}
-
-- (BOOL)canBecomeFirstResponder {
- return YES;
-}
-
-@end
-
-@implementation UIResponderNodeTestView
-
-- (BOOL)becomeFirstResponder {
- self.testIsFirstResponder = YES;
- return YES;
-}
-
-- (BOOL)canResignFirstResponder {
- return YES;
-}
-
-- (BOOL)resignFirstResponder {
- [super resignFirstResponder];
- if (self.testIsFirstResponder) {
- self.testIsFirstResponder = NO;
- return YES;
- }
- return NO;
-}
-
-@end
-
-@interface ASTestResponderNodeWithOverride : ASDisplayNode
-@end
-@implementation ASTestResponderNodeWithOverride
-- (BOOL)canBecomeFirstResponder {
- return YES;
-}
-@end
-
-@interface ASTestViewController: ASViewController
-@end
-@implementation ASTestViewController
-- (BOOL)prefersStatusBarHidden { return YES; }
-@end
-
-@interface UIResponderNodeTestDisplayViewCallingSuper : _ASDisplayView
-@end
-@implementation UIResponderNodeTestDisplayViewCallingSuper
-- (BOOL)canBecomeFirstResponder { return YES; }
-- (BOOL)becomeFirstResponder { return [super becomeFirstResponder]; }
-@end
-
-@interface UIResponderNodeTestViewCallingSuper : UIView
-@end
-@implementation UIResponderNodeTestViewCallingSuper
-- (BOOL)canBecomeFirstResponder { return YES; }
-- (BOOL)becomeFirstResponder { return [super becomeFirstResponder]; }
-@end
-
-@interface ASDisplayNodeTests : XCTestCase
-@end
-
-@implementation ASDisplayNodeTests
-{
- dispatch_queue_t queue;
-}
-
-- (void)testOverriddenNodeFirstResponderBehavior
-{
- ASTestDisplayNode *node = [[ASTestResponderNode alloc] init];
- XCTAssertTrue([node canBecomeFirstResponder]);
- XCTAssertTrue([node becomeFirstResponder]);
-}
-
-- (void)testOverriddenDisplayViewFirstResponderBehavior
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewClass:[UIResponderNodeTestDisplayViewCallingSuper class]];
-
- // We have to add the node to a window otherwise the super responder methods call responses are undefined
- // This will also create the backing view of the node
- [window addSubnode:node];
- [window makeKeyAndVisible];
-
- XCTAssertTrue([node canBecomeFirstResponder]);
- XCTAssertTrue([node becomeFirstResponder]);
-}
-
-- (void)testOverriddenViewFirstResponderBehavior
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewClass:[UIResponderNodeTestViewCallingSuper class]];
-
- // We have to add the node to a window otherwise the super responder methods call responses are undefined
- // This will also create the backing view of the node
- [window addSubnode:node];
- [window makeKeyAndVisible];
-
- XCTAssertTrue([node canBecomeFirstResponder]);
- XCTAssertTrue([node becomeFirstResponder]);
-}
-
-- (void)testDefaultFirstResponderBehavior
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- XCTAssertFalse([node canBecomeFirstResponder]);
- XCTAssertFalse([node becomeFirstResponder]);
-}
-
-- (void)testResponderMethodsBehavior
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASEditableTextNode *textNode = [[ASEditableTextNode alloc] init];
-
- // We have to add the text node to a window otherwise the responder methods responses are undefined
- // This will also create the backing view of the node
- [window addSubnode:textNode];
- [window makeKeyAndVisible];
-
- XCTAssertTrue([textNode canBecomeFirstResponder]);
- XCTAssertTrue([textNode becomeFirstResponder]);
- XCTAssertTrue([window firstResponder] == textNode.textView);
- XCTAssertTrue([textNode resignFirstResponder]);
-
- // If the textNode resigns it's first responder the view should not be the first responder
- XCTAssertTrue([window firstResponder] == nil);
- XCTAssertFalse([textNode.view isFirstResponder]);
-}
-
-- (void)testResponderOverrrideCanBecomeFirstResponder
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASTestResponderNodeWithOverride *node = [[ASTestResponderNodeWithOverride alloc] init];
-
- // We have to add the text node to a window otherwise the responder methods responses are undefined
- // This will also create the backing view of the node
- [window addSubnode:node];
- [window makeKeyAndVisible];
-
- XCTAssertTrue([node canBecomeFirstResponder]);
- XCTAssertTrue([node becomeFirstResponder]);
- XCTAssertTrue([window firstResponder] == node.view);
-}
-
-- (void)testUnsupportedResponderSetupWillThrow
-{
- ASTestResponderNode *node = [[ASTestResponderNode alloc] init];
- [node setViewBlock:^UIView * _Nonnull{
- return [[UIView alloc] init];
- }];
- XCTAssertThrows([node view], @"Externally provided views should be synchronous");
-}
-
-- (void)setUp
-{
- [super setUp];
- queue = dispatch_queue_create("com.facebook.AsyncDisplayKit.ASDisplayNodeTestsQueue", NULL);
-}
-
-- (void)testViewCreatedOffThreadCanBeRealizedOnThread
-{
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] init];
- }];
-
- UIView *view = node.view;
- XCTAssertNotNil(view, @"Getting node's view on-thread should succeed.");
-}
-
-- (void)testNodeCreatedOffThreadWithExistingView
-{
- UIView *view = [[UIDisplayNodeTestView alloc] init];
-
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
- return view;
- }];
- }];
-
- XCTAssertFalse(node.layerBacked, @"Can't be layer backed");
- XCTAssertTrue(node.synchronous, @"Node with plain view should be synchronous");
- XCTAssertFalse(node.nodeLoaded, @"Shouldn't have a view yet");
- XCTAssertEqual(view, node.view, @"Getting node's view on-thread should succeed.");
-}
-
-- (void)testNodeCreatedOffThreadWithLazyView
-{
- __block UIView *view = nil;
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
- XCTAssertTrue([NSThread isMainThread], @"View block must run on the main queue");
- view = [[UIDisplayNodeTestView alloc] init];
- return view;
- }];
- }];
-
- XCTAssertNil(view, @"View block should not be invoked yet");
- [node view];
- XCTAssertNotNil(view, @"View block should have been invoked");
- XCTAssertEqual(view, node.view, @"Getting node's view on-thread should succeed.");
- XCTAssertTrue(node.synchronous, @"Node with plain view should be synchronous");
-}
-
-- (void)testNodeCreatedWithLazyAsyncView
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{
- XCTAssertTrue([NSThread isMainThread], @"View block must run on the main queue");
- return [[_ASDisplayView alloc] init];
- }];
-
- XCTAssertThrows([node view], @"Externally provided views should be synchronous");
- XCTAssertTrue(node.synchronous, @"Node with externally provided view should be synchronous");
-}
-
-- (void)checkValuesMatchDefaults:(ASDisplayNode *)node isLayerBacked:(BOOL)isLayerBacked
-{
- NSString *targetName = isLayerBacked ? @"layer" : @"view";
- NSString *hasLoadedView = node.nodeLoaded ? @"with view" : [NSString stringWithFormat:@"after loading %@", targetName];
-
-// id rgbBlackCGColorIdPtr = (id)[UIColor blackColor].CGColor;
-
- XCTAssertEqual((id)nil, node.contents, @"default contents broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.clipsToBounds, @"default clipsToBounds broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.opaque, @"default opaque broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.needsDisplayOnBoundsChange, @"default needsDisplayOnBoundsChange broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.allowsGroupOpacity, @"default allowsGroupOpacity broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.allowsEdgeAntialiasing, @"default allowsEdgeAntialiasing broken %@", hasLoadedView);
- XCTAssertEqual((unsigned int)(kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge), node.edgeAntialiasingMask, @"default edgeAntialisingMask broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.hidden, @"default hidden broken %@", hasLoadedView);
- XCTAssertEqual(1.0f, node.alpha, @"default alpha broken %@", hasLoadedView);
- XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.bounds), @"default bounds broken %@", hasLoadedView);
- XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.frame), @"default frame broken %@", hasLoadedView);
- XCTAssertTrue(CGPointEqualToPoint(CGPointZero, node.position), @"default position broken %@", hasLoadedView);
- XCTAssertEqual((CGFloat)0.0, node.zPosition, @"default zPosition broken %@", hasLoadedView);
- XCTAssertEqual(1.0f, node.contentsScale, @"default contentsScale broken %@", hasLoadedView);
- XCTAssertEqual([UIScreen mainScreen].scale, node.contentsScaleForDisplay, @"default contentsScaleForDisplay broken %@", hasLoadedView);
- XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.transform), @"default transform broken %@", hasLoadedView);
- XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.subnodeTransform), @"default subnodeTransform broken %@", hasLoadedView);
- XCTAssertEqual((id)nil, node.backgroundColor, @"default backgroundColor broken %@", hasLoadedView);
- XCTAssertEqual(UIViewContentModeScaleToFill, node.contentMode, @"default contentMode broken %@", hasLoadedView);
-// XCTAssertEqualObjects(rgbBlackCGColorIdPtr, (id)node.shadowColor, @"default shadowColor broken %@", hasLoadedView);
- XCTAssertEqual(0.0f, node.shadowOpacity, @"default shadowOpacity broken %@", hasLoadedView);
- XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(0, -3), node.shadowOffset), @"default shadowOffset broken %@", hasLoadedView);
- XCTAssertEqual(3.f, node.shadowRadius, @"default shadowRadius broken %@", hasLoadedView);
- XCTAssertEqual(0.0f, node.borderWidth, @"default borderWidth broken %@", hasLoadedView);
-// XCTAssertEqualObjects(rgbBlackCGColorIdPtr, (id)node.borderColor, @"default borderColor broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.displaySuspended, @"default displaySuspended broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.displaysAsynchronously, @"default displaysAsynchronously broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.asyncdisplaykit_asyncTransactionContainer, @"default asyncdisplaykit_asyncTransactionContainer broken %@", hasLoadedView);
- XCTAssertEqualObjects(nil, node.debugName, @"default name broken %@", hasLoadedView);
-
- XCTAssertEqual(NO, node.isAccessibilityElement, @"default isAccessibilityElement is broken %@", hasLoadedView);
- XCTAssertEqual((id)nil, node.accessibilityLabel, @"default accessibilityLabel is broken %@", hasLoadedView);
- XCTAssertEqual((id)nil, node.accessibilityHint, @"default accessibilityHint is broken %@", hasLoadedView);
- XCTAssertEqual((id)nil, node.accessibilityValue, @"default accessibilityValue is broken %@", hasLoadedView);
-// if (AS_AT_LEAST_IOS11) {
-// XCTAssertEqual((id)nil, node.accessibilityAttributedLabel, @"default accessibilityAttributedLabel is broken %@", hasLoadedView);
-// XCTAssertEqual((id)nil, node.accessibilityAttributedHint, @"default accessibilityAttributedHint is broken %@", hasLoadedView);
-// XCTAssertEqual((id)nil, node.accessibilityAttributedValue, @"default accessibilityAttributedValue is broken %@", hasLoadedView);
-// }
- XCTAssertEqual(UIAccessibilityTraitNone, node.accessibilityTraits, @"default accessibilityTraits is broken %@", hasLoadedView);
- XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.accessibilityFrame), @"default accessibilityFrame is broken %@", hasLoadedView);
- XCTAssertEqual((id)nil, node.accessibilityLanguage, @"default accessibilityLanguage is broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.accessibilityElementsHidden, @"default accessibilityElementsHidden is broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.accessibilityViewIsModal, @"default accessibilityViewIsModal is broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.shouldGroupAccessibilityChildren, @"default shouldGroupAccessibilityChildren is broken %@", hasLoadedView);
-
- if (!isLayerBacked) {
- XCTAssertEqual(YES, node.userInteractionEnabled, @"default userInteractionEnabled broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.exclusiveTouch, @"default exclusiveTouch broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.autoresizesSubviews, @"default autoresizesSubviews broken %@", hasLoadedView);
- XCTAssertEqual(UIViewAutoresizingNone, node.autoresizingMask, @"default autoresizingMask broken %@", hasLoadedView);
- XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsMake(8, 8, 8, 8), node.layoutMargins), @"default layoutMargins broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.preservesSuperviewLayoutMargins, @"default preservesSuperviewLayoutMargins broken %@", hasLoadedView);
- XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, node.safeAreaInsets), @"default safeAreaInsets broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.insetsLayoutMarginsFromSafeArea, @"default insetsLayoutMarginsFromSafeArea broken %@", hasLoadedView);
- } else {
- XCTAssertEqual(NO, node.userInteractionEnabled, @"layer-backed nodes do not support userInteractionEnabled %@", hasLoadedView);
- XCTAssertEqual(NO, node.exclusiveTouch, @"layer-backed nodes do not support exclusiveTouch %@", hasLoadedView);
- }
-}
-
-- (void)checkDefaultPropertyValuesWithLayerBacking:(BOOL)isLayerBacked
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
-
- XCTAssertEqual(NO, node.isLayerBacked, @"default isLayerBacked broken without view");
- node.layerBacked = isLayerBacked;
- XCTAssertEqual(isLayerBacked, node.isLayerBacked, @"setIsLayerBacked: broken");
-
- // Assert that the values can be fetched from the node before the view is realized.
- [self checkValuesMatchDefaults:node isLayerBacked:isLayerBacked];
-
- [node layer]; // Force either view or layer loading
- XCTAssertTrue(node.nodeLoaded, @"Didn't load view");
-
- // Assert that the values can be fetched from the node after the view is realized.
- [self checkValuesMatchDefaults:node isLayerBacked:isLayerBacked];
-}
-
-- (void)testDefaultPropertyValuesLayer
-{
- [self checkDefaultPropertyValuesWithLayerBacking:YES];
-}
-
-- (void)testDefaultPropertyValuesView
-{
- [self checkDefaultPropertyValuesWithLayerBacking:NO];
-}
-
-- (UIImage *)bogusImage
-{
- static UIImage *bogusImage;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- UIGraphicsBeginImageContext(CGSizeMake(1, 1));
- bogusImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- });
- return bogusImage;
-}
-
-- (void)checkValuesMatchSetValues:(ASDisplayNode *)node isLayerBacked:(BOOL)isLayerBacked
-{
- NSString *targetName = isLayerBacked ? @"layer" : @"view";
- NSString *hasLoadedView = node.nodeLoaded ? @"with view" : [NSString stringWithFormat:@"after loading %@", targetName];
-
- XCTAssertEqual(isLayerBacked, node.isLayerBacked, @"isLayerBacked broken %@", hasLoadedView);
- XCTAssertEqualObjects((id)[self bogusImage].CGImage, (id)node.contents, @"contents broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.clipsToBounds, @"clipsToBounds broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.opaque, @"opaque broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.needsDisplayOnBoundsChange, @"needsDisplayOnBoundsChange broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.allowsGroupOpacity, @"allowsGroupOpacity broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.allowsEdgeAntialiasing, @"allowsEdgeAntialiasing broken %@", hasLoadedView);
- XCTAssertTrue((unsigned int)(kCALayerLeftEdge | kCALayerTopEdge) == node.edgeAntialiasingMask, @"edgeAntialiasingMask broken: %@", hasLoadedView);
- XCTAssertEqual(YES, node.hidden, @"hidden broken %@", hasLoadedView);
- XCTAssertEqual(.5f, node.alpha, @"alpha broken %@", hasLoadedView);
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 15, 42, 115.2), node.bounds), @"bounds broken %@", hasLoadedView);
- XCTAssertTrue(CGPointEqualToPoint(CGPointMake(10, 65), node.position), @"position broken %@", hasLoadedView);
- XCTAssertEqual((CGFloat)5.6, node.zPosition, @"zPosition broken %@", hasLoadedView);
- XCTAssertEqual(.5f, node.contentsScale, @"contentsScale broken %@", hasLoadedView);
- XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeScale(0.5, 0.5, 1.0), node.transform), @"transform broken %@", hasLoadedView);
- XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeTranslation(1337, 7357, 7007), node.subnodeTransform), @"subnodeTransform broken %@", hasLoadedView);
- XCTAssertEqualObjects([UIColor clearColor], node.backgroundColor, @"backgroundColor broken %@", hasLoadedView);
- XCTAssertEqual(UIViewContentModeBottom, node.contentMode, @"contentMode broken %@", hasLoadedView);
- XCTAssertEqual([[UIColor cyanColor] CGColor], node.shadowColor, @"shadowColor broken %@", hasLoadedView);
- XCTAssertEqual(.5f, node.shadowOpacity, @"shadowOpacity broken %@", hasLoadedView);
- XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(1.0f, 1.0f), node.shadowOffset), @"shadowOffset broken %@", hasLoadedView);
- XCTAssertEqual(.5f, node.shadowRadius, @"shadowRadius broken %@", hasLoadedView);
- XCTAssertEqual(.5f, node.borderWidth, @"borderWidth broken %@", hasLoadedView);
- XCTAssertEqual([[UIColor orangeColor] CGColor], node.borderColor, @"borderColor broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.displaySuspended, @"displaySuspended broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.displaysAsynchronously, @"displaySuspended broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.asyncdisplaykit_asyncTransactionContainer, @"asyncTransactionContainer broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.userInteractionEnabled, @"userInteractionEnabled broken %@", hasLoadedView);
- XCTAssertEqual((BOOL)!isLayerBacked, node.exclusiveTouch, @"exclusiveTouch broken %@", hasLoadedView);
- XCTAssertEqualObjects(@"quack like a duck", node.debugName, @"debugName broken %@", hasLoadedView);
-
- XCTAssertEqual(YES, node.isAccessibilityElement, @"accessibilityElement broken %@", hasLoadedView);
- XCTAssertEqualObjects(@"Ship love", node.accessibilityLabel, @"accessibilityLabel broken %@", hasLoadedView);
- XCTAssertEqualObjects(@"Awesome things will happen", node.accessibilityHint, @"accessibilityHint broken %@", hasLoadedView);
- XCTAssertEqualObjects(@"1 of 2", node.accessibilityValue, @"accessibilityValue broken %@", hasLoadedView);
-
- // setting the accessibilityLabel, accessibilityHint and accessibilityValue is supposed to be bridged to the attributed versions
-// if (AS_AT_LEAST_IOS11) {
-// XCTAssertEqualObjects(@"Ship love", node.accessibilityAttributedLabel.string, @"accessibilityAttributedLabel is broken %@", hasLoadedView);
-// XCTAssertEqualObjects(@"Awesome things will happen", node.accessibilityAttributedHint.string, @"accessibilityAttributedHint is broken %@", hasLoadedView);
-// XCTAssertEqualObjects(@"1 of 2", node.accessibilityAttributedValue.string, @"accessibilityAttributedValue is broken %@", hasLoadedView);
-// }
- XCTAssertEqual(UIAccessibilityTraitSelected | UIAccessibilityTraitButton, node.accessibilityTraits, @"accessibilityTraits broken %@", hasLoadedView);
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(1, 2, 3, 4), node.accessibilityFrame), @"accessibilityFrame broken %@", hasLoadedView);
- XCTAssertEqualObjects(@"mas", node.accessibilityLanguage, @"accessibilityLanguage broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.accessibilityElementsHidden, @"accessibilityElementsHidden broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.accessibilityViewIsModal, @"accessibilityViewIsModal broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.shouldGroupAccessibilityChildren, @"shouldGroupAccessibilityChildren broken %@", hasLoadedView);
- XCTAssertEqual(UIAccessibilityNavigationStyleSeparate, node.accessibilityNavigationStyle, @"accessibilityNavigationStyle broken %@", hasLoadedView);
- XCTAssertTrue(CGPointEqualToPoint(CGPointMake(1.0, 1.0), node.accessibilityActivationPoint), @"accessibilityActivationPoint broken %@", hasLoadedView);
- XCTAssertNotNil(node.accessibilityPath, @"accessibilityPath broken %@", hasLoadedView);
-
-
- if (!isLayerBacked) {
- XCTAssertEqual(UIViewAutoresizingFlexibleLeftMargin, node.autoresizingMask, @"autoresizingMask %@", hasLoadedView);
- XCTAssertEqual(NO, node.autoresizesSubviews, @"autoresizesSubviews broken %@", hasLoadedView);
- XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsMake(3, 5, 8, 11), node.layoutMargins), @"layoutMargins broken %@", hasLoadedView);
- XCTAssertEqual(YES, node.preservesSuperviewLayoutMargins, @"preservesSuperviewLayoutMargins broken %@", hasLoadedView);
- XCTAssertEqual(NO, node.insetsLayoutMarginsFromSafeArea, @"insetsLayoutMarginsFromSafeArea broken %@", hasLoadedView);
- }
-}
-
-- (void)checkSimpleBridgePropertiesSetPropagate:(BOOL)isLayerBacked
-{
- __block ASDisplayNode *node = nil;
-
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] init];
- node.layerBacked = isLayerBacked;
-
- node.contents = (id)[self bogusImage].CGImage;
- node.clipsToBounds = YES;
- node.opaque = NO;
- node.needsDisplayOnBoundsChange = YES;
- node.allowsGroupOpacity = NO;
- node.allowsEdgeAntialiasing = YES;
- node.edgeAntialiasingMask = (kCALayerLeftEdge | kCALayerTopEdge);
- node.hidden = YES;
- node.alpha = .5f;
- node.position = CGPointMake(10, 65);
- node.zPosition = 5.6;
- node.bounds = CGRectMake(10, 15, 42, 115.2);
- node.contentsScale = .5f;
- node.transform = CATransform3DMakeScale(0.5, 0.5, 1.0);
- node.subnodeTransform = CATransform3DMakeTranslation(1337, 7357, 7007);
- node.backgroundColor = [UIColor clearColor];
- node.contentMode = UIViewContentModeBottom;
- node.shadowColor = [[UIColor cyanColor] CGColor];
- node.shadowOpacity = .5f;
- node.shadowOffset = CGSizeMake(1.0f, 1.0f);
- node.shadowRadius = .5f;
- node.borderWidth = .5f;
- node.borderColor = [[UIColor orangeColor] CGColor];
- node.displaySuspended = YES;
- node.displaysAsynchronously = NO;
- node.asyncdisplaykit_asyncTransactionContainer = YES;
- node.userInteractionEnabled = NO;
- node.debugName = @"quack like a duck";
-
- node.isAccessibilityElement = YES;
-
- for (int i = 0; i < 4; i++) {
- if (i % 2 == 0) {
- XCTAssertNoThrow(node.accessibilityLabel = nil);
- XCTAssertNoThrow(node.accessibilityHint = nil);
- XCTAssertNoThrow(node.accessibilityValue = nil);
- } else {
- node.accessibilityLabel = @"Ship love";
- node.accessibilityHint = @"Awesome things will happen";
- node.accessibilityValue = @"1 of 2";
- }
- }
-
- node.accessibilityTraits = UIAccessibilityTraitSelected | UIAccessibilityTraitButton;
- node.accessibilityFrame = CGRectMake(1, 2, 3, 4);
- node.accessibilityLanguage = @"mas";
- node.accessibilityElementsHidden = YES;
- node.accessibilityViewIsModal = YES;
- node.shouldGroupAccessibilityChildren = YES;
- node.accessibilityNavigationStyle = UIAccessibilityNavigationStyleSeparate;
- node.accessibilityActivationPoint = CGPointMake(1.0, 1.0);
- node.accessibilityPath = [UIBezierPath bezierPath];
-
- if (!isLayerBacked) {
- node.exclusiveTouch = YES;
- node.autoresizesSubviews = NO;
- node.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
- node.insetsLayoutMarginsFromSafeArea = NO;
- node.layoutMargins = UIEdgeInsetsMake(3, 5, 8, 11);
- node.preservesSuperviewLayoutMargins = YES;
- }
- }];
-
- // Assert that the values can be fetched from the node before the view is realized.
- [self checkValuesMatchSetValues:node isLayerBacked:isLayerBacked];
-
- // Assert that the realized view/layer have the correct values.
- [node layer];
-
- [self checkValuesMatchSetValues:node isLayerBacked:isLayerBacked];
-
- // As a final sanity check, change a value on the realized view and ensure it is fetched through the node.
- if (isLayerBacked) {
- node.layer.hidden = NO;
- } else {
- node.view.hidden = NO;
- }
- XCTAssertEqual(NO, node.hidden, @"After the view is realized, the node should delegate properties to the view.");
-}
-
-// Set each of the simple bridged UIView properties to a non-default value off-thread, then
-// assert that they are correct on the node and propagated to the UIView realized on-thread.
-- (void)testSimpleUIViewBridgePropertiesSetOffThreadPropagate
-{
- [self checkSimpleBridgePropertiesSetPropagate:NO];
-}
-
-- (void)testSimpleCALayerBridgePropertiesSetOffThreadPropagate
-{
- [self checkSimpleBridgePropertiesSetPropagate:YES];
-}
-
-- (void)testPropertiesSetOffThreadBeforeLoadingExternalView
-{
- UIView *view = [[UIDisplayNodeTestView alloc] init];
-
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] initWithViewBlock:^{
- return view;
- }];
- node.backgroundColor = [UIColor blueColor];
- node.frame = CGRectMake(10, 20, 30, 40);
- node.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- node.userInteractionEnabled = YES;
- }];
-
- [self checkExternalViewAppliedPropertiesMatch:node];
-}
-
-- (void)testPropertiesSetOnThreadAfterLoadingExternalView
-{
- UIView *view = [[UIDisplayNodeTestView alloc] init];
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewBlock:^{
- return view;
- }];
-
- // Load the backing view first
- [node view];
-
- node.backgroundColor = [UIColor blueColor];
- node.frame = CGRectMake(10, 20, 30, 40);
- node.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- node.userInteractionEnabled = YES;
-
- [self checkExternalViewAppliedPropertiesMatch:node];
-}
-
-- (void)checkExternalViewAppliedPropertiesMatch:(ASDisplayNode *)node
-{
- UIView *view = node.view;
-
- XCTAssertEqualObjects([UIColor blueColor], view.backgroundColor, @"backgroundColor not propagated to view");
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 20, 30, 40), view.frame), @"frame not propagated to view");
- XCTAssertEqual(UIViewAutoresizingFlexibleWidth, view.autoresizingMask, @"autoresizingMask not propagated to view");
- XCTAssertEqual(YES, view.userInteractionEnabled, @"userInteractionEnabled not propagated to view");
-}
-
-- (void)testPropertiesSetOffThreadBeforeLoadingExternalLayer
-{
- CALayer *layer = [[CAShapeLayer alloc] init];
-
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] initWithLayerBlock:^{
- return layer;
- }];
- node.backgroundColor = [UIColor blueColor];
- node.frame = CGRectMake(10, 20, 30, 40);
- }];
-
- [self checkExternalLayerAppliedPropertiesMatch:node];
-}
-
-- (void)testPropertiesSetOnThreadAfterLoadingExternalLayer
-{
- CALayer *layer = [[CAShapeLayer alloc] init];
- ASDisplayNode *node = [[ASDisplayNode alloc] initWithLayerBlock:^{
- return layer;
- }];
-
- // Load the backing layer first
- [node layer];
-
- node.backgroundColor = [UIColor blueColor];
- node.frame = CGRectMake(10, 20, 30, 40);
-
- [self checkExternalLayerAppliedPropertiesMatch:node];
-}
-
-- (void)checkExternalLayerAppliedPropertiesMatch:(ASDisplayNode *)node
-{
- CALayer *layer = node.layer;
-
- XCTAssertTrue(CGColorEqualToColor([UIColor blueColor].CGColor, layer.backgroundColor), @"backgroundColor not propagated to layer");
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 20, 30, 40), layer.frame), @"frame not propagated to layer");
-}
-
-
-// Perform parallel updates of a standard UIView/CALayer and an ASDisplayNode and ensure they are equivalent.
-- (void)testDeriveFrameFromBoundsPositionAnchorPoint
-{
- UIView *plainView = [[UIView alloc] initWithFrame:CGRectZero];
- plainView.layer.anchorPoint = CGPointMake(0.25f, 0.75f);
- plainView.layer.position = CGPointMake(10, 20);
- plainView.layer.bounds = CGRectMake(0, 0, 60, 80);
-
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] init];
- node.anchorPoint = CGPointMake(0.25f, 0.75f);
- node.bounds = CGRectMake(0, 0, 60, 80);
- node.position = CGPointMake(10, 20);
- }];
-
- XCTAssertTrue(CGRectEqualToRect(plainView.frame, node.frame), @"Node frame should match UIView frame before realization.");
- XCTAssertTrue(CGRectEqualToRect(plainView.frame, node.view.frame), @"Realized view frame should match UIView frame.");
-}
-
-// Perform parallel updates of a standard UIView/CALayer and an ASDisplayNode and ensure they are equivalent.
-- (void)testSetFrameSetsBoundsPosition
-{
- UIView *plainView = [[UIView alloc] initWithFrame:CGRectZero];
- plainView.layer.anchorPoint = CGPointMake(0.25f, 0.75f);
- plainView.layer.frame = CGRectMake(10, 20, 60, 80);
-
- __block ASDisplayNode *node = nil;
- [self executeOffThread:^{
- node = [[ASDisplayNode alloc] init];
- node.anchorPoint = CGPointMake(0.25f, 0.75f);
- node.frame = CGRectMake(10, 20, 60, 80);
- }];
-
- XCTAssertTrue(CGPointEqualToPoint(plainView.layer.position, node.position), @"Node position should match UIView position before realization.");
- XCTAssertTrue(CGRectEqualToRect(plainView.layer.bounds, node.bounds), @"Node bounds should match UIView bounds before realization.");
- XCTAssertTrue(CGPointEqualToPoint(plainView.layer.position, node.view.layer.position), @"Realized view position should match UIView position before realization.");
- XCTAssertTrue(CGRectEqualToRect(plainView.layer.bounds, node.view.layer.bounds), @"Realized view bounds should match UIView bounds before realization.");
-}
-
-- (void)testDisplayNodePointConversionWithFrames
-{
- ASDisplayNode *node = nil;
- ASDisplayNode *innerNode = nil;
-
- // Setup
- CGPoint originalPoint = CGPointZero, convertedPoint = CGPointZero, correctPoint = CGPointZero;
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* outer node's coordinate space to inner node's coordinate space
- node.frame = CGRectMake(100, 100, 100, 100);
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(105, 105);
- correctPoint = CGPointMake(95, 95);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:node selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* inner node's coordinate space to outer node's coordinate space
- node.frame = CGRectMake(100, 100, 100, 100);
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(5, 5);
- correctPoint = CGPointMake(15, 15);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:node];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in inner node's coordinate space *TO* outer node's coordinate space
- node.frame = CGRectMake(100, 100, 100, 100);
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(95, 95);
- correctPoint = CGPointMake(105, 105);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:node selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in outer node's coordinate space *TO* inner node's coordinate space
- node.frame = CGRectMake(0, 0, 100, 100);
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(5, 5);
- correctPoint = CGPointMake(-5, -5);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:node];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-}
-
-// Test conversions when bounds is not null.
-// NOTE: Esoteric values were picked to facilitate visual inspection by demonstrating the relevance of certain numbers and lack of relevance of others
-- (void)testDisplayNodePointConversionWithNonZeroBounds
-{
- ASDisplayNode *node = nil;
- ASDisplayNode *innerNode = nil;
-
- // Setup
- CGPoint originalPoint = CGPointZero, convertedPoint = CGPointZero, correctPoint = CGPointZero;
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* outer node's coordinate space to inner node's coordinate space
- node.anchorPoint = CGPointZero;
- innerNode.anchorPoint = CGPointZero;
- node.bounds = CGRectMake(20, 20, 100, 100);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(42, 42);
- correctPoint = CGPointMake(36, 36);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:node selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* inner node's coordinate space to outer node's coordinate space
- node.anchorPoint = CGPointZero;
- innerNode.anchorPoint = CGPointZero;
- node.bounds = CGRectMake(-1000, -1000, 1337, 1337);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 200, 200);
- originalPoint = CGPointMake(5, 5);
- correctPoint = CGPointMake(11, 11);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:node];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in inner node's coordinate space *TO* outer node's coordinate space
- node.anchorPoint = CGPointZero;
- innerNode.anchorPoint = CGPointZero;
- node.bounds = CGRectMake(20, 20, 100, 100);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(36, 36);
- correctPoint = CGPointMake(42, 42);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:node selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in outer node's coordinate space *TO* inner node's coordinate space
- node.anchorPoint = CGPointZero;
- innerNode.anchorPoint = CGPointZero;
- node.bounds = CGRectMake(-1000, -1000, 1337, 1337);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 200, 200);
- originalPoint = CGPointMake(11, 11);
- correctPoint = CGPointMake(5, 5);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:node];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-}
-
-// Test conversions when the anchorPoint is not {0.0, 0.0}.
-- (void)testDisplayNodePointConversionWithNonZeroAnchorPoint
-{
- ASDisplayNode *node = nil;
- ASDisplayNode *innerNode = nil;
-
- // Setup
- CGPoint originalPoint = CGPointZero, convertedPoint = CGPointZero, correctPoint = CGPointZero;
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* outer node's coordinate space to inner node's coordinate space
- node.bounds = CGRectMake(20, 20, 100, 100);
- innerNode.anchorPoint = CGPointMake(0.75, 1);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(42, 42);
- correctPoint = CGPointMake(51, 56);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:node selfNode:innerNode];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(convertedPoint, correctPoint, 0.001), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point *FROM* inner node's coordinate space to outer node's coordinate space
- node.bounds = CGRectMake(-1000, -1000, 1337, 1337);
- innerNode.anchorPoint = CGPointMake(0.3, 0.3);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 200, 200);
- originalPoint = CGPointMake(55, 55);
- correctPoint = CGPointMake(1, 1);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:node];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(convertedPoint, correctPoint, 0.001), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in inner node's coordinate space *TO* outer node's coordinate space
- node.bounds = CGRectMake(20, 20, 100, 100);
- innerNode.anchorPoint = CGPointMake(0.75, 1);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(51, 56);
- correctPoint = CGPointMake(42, 42);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:node selfNode:innerNode];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(convertedPoint, correctPoint, 0.001), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-
- // Setup
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
- [node addSubnode:innerNode];
-
- // Convert point in outer node's coordinate space *TO* inner node's coordinate space
- node.bounds = CGRectMake(-1000, -1000, 1337, 1337);
- innerNode.anchorPoint = CGPointMake(0.3, 0.3);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 200, 200);
- originalPoint = CGPointMake(1, 1);
- correctPoint = CGPointMake(55, 55);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:node];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(convertedPoint, correctPoint, 0.001), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-}
-
-- (void)testDisplayNodePointConversionAgainstSelf {
- ASDisplayNode *innerNode = nil;
- CGPoint originalPoint = CGPointZero, convertedPoint = CGPointZero;
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(105, 105);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:innerNode];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(convertedPoint, originalPoint, 0.001), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(42, 42);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, originalPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.anchorPoint = CGPointMake(0.3, 0.3);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 200, 200);
- originalPoint = CGPointMake(55, 55);
- convertedPoint = [self checkConvertPoint:originalPoint fromNode:innerNode selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, originalPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.frame = CGRectMake(10, 10, 20, 20);
- originalPoint = CGPointMake(95, 95);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, originalPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(36, 36);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, originalPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-
- innerNode = [[ASDisplayNode alloc] init];
- innerNode.anchorPoint = CGPointMake(0.75, 1);
- innerNode.position = CGPointMake(23, 23);
- innerNode.bounds = CGRectMake(17, 17, 20, 20);
- originalPoint = CGPointMake(51, 56);
- convertedPoint = [self checkConvertPoint:originalPoint toNode:innerNode selfNode:innerNode];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, originalPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(convertedPoint));
-}
-
-- (void)testDisplayNodePointConversionFailureFromDisjointHierarchies
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- ASDisplayNode *childNode = [[ASDisplayNode alloc] init];
- ASDisplayNode *otherNode = [[ASDisplayNode alloc] init];
- [node addSubnode:childNode];
-
- XCTAssertNoThrow([self checkConvertPoint:CGPointZero fromNode:node selfNode:childNode], @"Assertion should have succeeded; nodes are in the same hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero fromNode:node selfNode:otherNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero fromNode:childNode selfNode:otherNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
-
- XCTAssertNoThrow([self checkConvertPoint:CGPointZero fromNode:childNode selfNode:node], @"Assertion should have succeeded; nodes are in the same hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero fromNode:otherNode selfNode:node], @"Assertion should have failed for nodes that are not in the same node hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero fromNode:otherNode selfNode:childNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
-
- XCTAssertNoThrow([self checkConvertPoint:CGPointZero toNode:node selfNode:childNode], @"Assertion should have succeeded; nodes are in the same hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero toNode:node selfNode:otherNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero toNode:childNode selfNode:otherNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
-
- XCTAssertNoThrow([self checkConvertPoint:CGPointZero toNode:childNode selfNode:node], @"Assertion should have succeeded; nodes are in the same hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero toNode:otherNode selfNode:node], @"Assertion should have failed for nodes that are not in the same node hierarchy");
- XCTAssertThrows([self checkConvertPoint:CGPointZero toNode:otherNode selfNode:childNode], @"Assertion should have failed for nodes that are not in the same node hierarchy");
-}
-
-- (void)testDisplayNodePointConversionOnDeepHierarchies
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
-
- // 7 deep (six below root); each one positioned at position = (1, 1)
- _addTonsOfSubnodes(node, 2, 6, ^(ASDisplayNode *createdNode) {
- createdNode.position = CGPointMake(1, 1);
- });
-
- ASDisplayNode *deepSubNode = [self _getDeepSubnodeForRoot:node withIndices:@[@1, @1, @1, @1, @1, @1]];
-
- CGPoint originalPoint = CGPointMake(55, 55);
- CGPoint correctPoint = CGPointMake(61, 61);
- CGPoint convertedPoint = [deepSubNode convertPoint:originalPoint toNode:node];
- XCTAssertTrue(CGPointEqualToPoint(convertedPoint, correctPoint), @"Unexpected point conversion result. Point: %@ Expected conversion: %@ Actual conversion: %@", NSStringFromCGPoint(originalPoint), NSStringFromCGPoint(correctPoint), NSStringFromCGPoint(convertedPoint));
-}
-
-// Adds nodes (breadth-first rather than depth-first addition)
-static void _addTonsOfSubnodes(ASDisplayNode *parent, NSUInteger fanout, NSUInteger depth, void (^onCreate)(ASDisplayNode *createdNode)) {
- if (depth == 0) {
- return;
- }
-
- for (NSUInteger i = 0; i < fanout; i++) {
- ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
- [parent addSubnode:subnode];
- onCreate(subnode);
- }
- for (NSUInteger i = 0; i < fanout; i++) {
- _addTonsOfSubnodes(parent.subnodes[i], fanout, depth - 1, onCreate);
- }
-}
-
-// Convenience function for getting a node deep within a node hierarchy
-- (ASDisplayNode *)_getDeepSubnodeForRoot:(ASDisplayNode *)root withIndices:(NSArray *)indexArray {
- if ([indexArray count] == 0) {
- return root;
- }
-
- NSArray *subnodes = root.subnodes;
- if ([subnodes count] == 0) {
- XCTFail(@"Node hierarchy isn't deep enough for given index array");
- }
-
- NSUInteger index = [indexArray[0] unsignedIntegerValue];
- NSArray *otherIndices = [indexArray subarrayWithRange:NSMakeRange(1, [indexArray count] -1)];
-
- return [self _getDeepSubnodeForRoot:subnodes[index] withIndices:otherIndices];
-}
-
-static inline BOOL _CGPointEqualToPointWithEpsilon(CGPoint point1, CGPoint point2, CGFloat epsilon) {
- CGFloat absEpsilon = fabs(epsilon);
- BOOL xOK = fabs(point1.x - point2.x) < absEpsilon;
- BOOL yOK = fabs(point1.y - point2.y) < absEpsilon;
- return xOK && yOK;
-}
-
-- (CGPoint)checkConvertPoint:(CGPoint)point fromNode:(ASDisplayNode *)fromNode selfNode:(ASDisplayNode *)toNode
-{
- CGPoint nodeConversion = [toNode convertPoint:point fromNode:fromNode];
-
- UIView *fromView = fromNode.view;
- UIView *toView = toNode.view;
- CGPoint viewConversion = [toView convertPoint:point fromView:fromView];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(nodeConversion, viewConversion, 0.001), @"Conversion mismatch: node: %@ view: %@", NSStringFromCGPoint(nodeConversion), NSStringFromCGPoint(viewConversion));
- return nodeConversion;
-}
-
-- (CGPoint)checkConvertPoint:(CGPoint)point toNode:(ASDisplayNode *)toNode selfNode:(ASDisplayNode *)fromNode
-{
- CGPoint nodeConversion = [fromNode convertPoint:point toNode:toNode];
-
- UIView *fromView = fromNode.view;
- UIView *toView = toNode.view;
- CGPoint viewConversion = [fromView convertPoint:point toView:toView];
- XCTAssertTrue(_CGPointEqualToPointWithEpsilon(nodeConversion, viewConversion, 0.001), @"Conversion mismatch: node: %@ view: %@", NSStringFromCGPoint(nodeConversion), NSStringFromCGPoint(viewConversion));
- return nodeConversion;
-}
-
-- (void)executeOffThread:(void (^)(void))block
-{
- __block BOOL blockExecuted = NO;
- dispatch_group_t g = dispatch_group_create();
- dispatch_group_async(g, queue, ^{
- block();
- blockExecuted = YES;
- });
- dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
- XCTAssertTrue(blockExecuted, @"Block did not finish executing. Timeout or exception?");
-}
-
-- (void)testReferenceCounting
-{
- __weak ASTestDisplayNode *weakNode = nil;
- {
- NS_VALID_UNTIL_END_OF_SCOPE ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- weakNode = node;
- }
- XCTAssertNil(weakNode);
-}
-
-- (void)testAddingNodeToHierarchyRetainsNode
-{
- UIView *v = [[UIView alloc] initWithFrame:CGRectZero];
- __weak ASTestDisplayNode *weakNode = nil;
- {
- NS_VALID_UNTIL_END_OF_SCOPE ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- [v addSubview:node.view];
- weakNode = node;
- }
- XCTAssertNotNil(weakNode);
-}
-
-- (void)testAddingSubnodeDoesNotCreateRetainCycle
-{
- __weak ASTestDisplayNode *weakNode = nil;
- __weak ASTestDisplayNode *weakSubnode = nil;
- {
- NS_VALID_UNTIL_END_OF_SCOPE ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- NS_VALID_UNTIL_END_OF_SCOPE ASTestDisplayNode *subnode = [[ASTestDisplayNode alloc] init];
- [node addSubnode:subnode];
- weakNode = node;
- weakSubnode = subnode;
-
- XCTAssertNotNil(weakNode);
- XCTAssertNotNil(weakSubnode);
- }
- XCTAssertNil(weakNode);
- XCTAssertNil(weakSubnode);
-}
-
-- (void)testThatUIKitDeallocationTrampoliningWorks
-{
- NS_VALID_UNTIL_END_OF_SCOPE __weak UIGestureRecognizer *weakRecognizer = nil;
- NS_VALID_UNTIL_END_OF_SCOPE __weak UIGestureRecognizer *weakIdRecognizer = nil;
- NS_VALID_UNTIL_END_OF_SCOPE __weak UIView *weakView = nil;
- NS_VALID_UNTIL_END_OF_SCOPE __weak CALayer *weakLayer = nil;
- NS_VALID_UNTIL_END_OF_SCOPE __weak UIImage *weakImage = nil;
- NS_VALID_UNTIL_END_OF_SCOPE __weak NSArray *weakArray = nil;
- __block NS_VALID_UNTIL_END_OF_SCOPE ASTestDisplayNode *node = nil;
- @autoreleasepool {
- node = [[ASTestDisplayNode alloc] init];
- node.gestureRecognizer = [[UIGestureRecognizer alloc] init];
- node.idGestureRecognizer = [[UIGestureRecognizer alloc] init];
- UIGraphicsBeginImageContextWithOptions(CGSizeMake(1000, 1000), YES, 1);
- node.bigImage = UIGraphicsGetImageFromCurrentImageContext();
- node.randomProperty = @[ @"Hello, world!" ];
- UIGraphicsEndImageContext();
- weakImage = node.bigImage;
- weakView = node.view;
- weakLayer = node.layer;
- weakArray = node.randomProperty;
- weakIdRecognizer = node.idGestureRecognizer;
- weakRecognizer = node.gestureRecognizer;
- }
-
- [self executeOffThread:^{
- node = nil;
- }];
-
- XCTAssertNotNil(weakRecognizer, @"UIGestureRecognizer ivars should be deallocated on main.");
- XCTAssertNotNil(weakIdRecognizer, @"UIGestureRecognizer-backed 'id' ivars should be deallocated on main.");
- XCTAssertNotNil(weakView, @"UIView ivars should be deallocated on main.");
- XCTAssertNotNil(weakLayer, @"CALayer ivars should be deallocated on main.");
- XCTAssertNil(weakImage, @"UIImage ivars should be deallocated normally.");
- XCTAssertNil(weakArray, @"NSArray ivars should be deallocated normally.");
- XCTAssertNil(node);
-
- [self expectationForPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary * _Nullable bindings) {
- return (weakRecognizer == nil && weakIdRecognizer == nil && weakView == nil);
- }] evaluatedWithObject:(id)kCFNull handler:nil];
- [self waitForExpectationsWithTimeout:10 handler:nil];
-}
-
-- (void)testSubnodes
-{
- ASDisplayNode *parent = [[ASDisplayNode alloc] init];
- ASDisplayNode *nilNode = nil;
- XCTAssertThrows([parent addSubnode:nilNode], @"Don't try to add nil, but we'll deal with it in production, but throw in development.");
- XCTAssertNoThrow([parent addSubnode:parent], @"Not good, test that we recover");
- XCTAssertEqual(0u, parent.subnodes.count, @"We shouldn't have any subnodes");
-}
-
-- (void)testReplaceSubnodeNoView
-{
- [self checkReplaceSubnodeLoaded:NO layerBacked:NO];
-}
-
-- (void)testReplaceSubnodeNoLayer
-{
- [self checkReplaceSubnodeLoaded:NO layerBacked:YES];
-}
-
-- (void)testReplaceSubnodeView
-{
- [self checkReplaceSubnodeLoaded:YES layerBacked:NO];
-}
-
-- (void)testReplaceSubnodeLayer
-{
- [self checkReplaceSubnodeLoaded:YES layerBacked:YES];
-}
-
-
-- (void)checkReplaceSubnodeLoaded:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
-{
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareNodeNamed(d);
-
- for (ASDisplayNode *n in @[parent, a, b, c, d]) {
- n.layerBacked = isLayerBacked;
- }
-
- [parent addSubnode:a];
- [parent addSubnode:b];
- [parent addSubnode:c];
-
- if (loaded) {
- [parent layer];
- }
-
- if (loaded) {
- XCTAssertFalse(d.nodeLoaded, @"Should not yet be loaded");
- }
-
- // Shut the type mismatch up
- ASDisplayNode *nilParent = nil;
-
- // Check initial state
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"initial state");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Check replace 0th
- [parent replaceSubnode:a withSubnode:d];
-
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"d,b,c", @"after replace 0th");
- XCTAssertNodesHaveParent(parent, d, b, c);
- XCTAssertNodesHaveParent(nilParent, a);
- if (loaded) {
- XCTAssertNodesLoaded(d);
- }
-
- [parent replaceSubnode:d withSubnode:a];
-
- // Check replace 1st
- [parent replaceSubnode:b withSubnode:d];
-
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,d,c", @"Replace");
- XCTAssertNodesHaveParent(parent, a, c, d);
- XCTAssertNodesHaveParent(nilParent, b);
-
- [parent replaceSubnode:d withSubnode:b];
-
- // Check replace 2nd
- [parent replaceSubnode:c withSubnode:d];
-
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,d", @"Replace");
- XCTAssertNodesHaveParent(parent, a, b, d);
- XCTAssertNodesHaveParent(nilParent, c);
-
- [parent replaceSubnode:d withSubnode:c];
-
- //Check initial again
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"check should back to initial");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Check replace 0th with 2nd
- [parent replaceSubnode:a withSubnode:c];
-
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,b", @"After replace 0th");
- XCTAssertNodesHaveParent(parent, c, b);
- XCTAssertNodesHaveParent(nilParent, a,d);
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-- (void)testInsertSubnodeAtIndexView
-{
- [self checkInsertSubnodeAtIndexWithViewLoaded:YES layerBacked:NO];
-}
-
-- (void)testInsertSubnodeAtIndexLayer
-{
- [self checkInsertSubnodeAtIndexWithViewLoaded:YES layerBacked:YES];
-}
-
-- (void)testInsertSubnodeAtIndexNoView
-{
- [self checkInsertSubnodeAtIndexWithViewLoaded:NO layerBacked:NO];
-}
-
-- (void)testInsertSubnodeAtIndexNoLayer
-{
- [self checkInsertSubnodeAtIndexWithViewLoaded:NO layerBacked:YES];
-}
-
-- (void)checkInsertSubnodeAtIndexWithViewLoaded:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
-{
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
-
- for (ASDisplayNode *v in @[parent, a, b, c]) {
- v.layerBacked = isLayerBacked;
- }
-
- // Load parent
- if (loaded) {
- (void)[parent layer];
- }
-
- // Add another subnode to test creation after parent is loaded
- DeclareNodeNamed(d);
- d.layerBacked = isLayerBacked;
- if (loaded) {
- XCTAssertFalse(d.nodeLoaded, @"Should not yet be loaded");
- }
-
- // Shut the type mismatch up
- ASDisplayNode *nilParent = nil;
-
- // Check initial state
- XCTAssertEqual(0u, parent.subnodes.count, @"Should have the right subnode count");
-
- // Check insert at 0th () => (a,b,c)
- [parent insertSubnode:c atIndex:0];
- [parent insertSubnode:b atIndex:0];
- [parent insertSubnode:a atIndex:0];
-
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"initial state");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- if (loaded) {
- XCTAssertNodesLoaded(a, b, c);
- } else {
- XCTAssertNodesNotLoaded(a, b, c);
- }
-
- // Check insert at 1st (a,b,c) => (a,d,b,c)
- [parent insertSubnode:d atIndex:1];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,d,b,c", @"initial state");
- XCTAssertNodesHaveParent(parent, a, b, c, d);
- if (loaded) {
- XCTAssertNodesLoaded(d);
- }
-
- // Reset
- [d removeFromSupernode];
- XCTAssertEqual(3u, parent.subnodes.count, @"Should have the right subnode count");
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"Bad removal of d");
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Check insert at last position
- [parent insertSubnode:d atIndex:3];
-
- XCTAssertEqual(4u, parent.subnodes.count, @"Should have the right subnode count");
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c,d", @"insert at last position.");
- XCTAssertNodesHaveParent(parent, a, b, c, d);
-
- // Reset
- [d removeFromSupernode];
- XCTAssertEqual(3u, parent.subnodes.count, @"Should have the right subnode count");
- XCTAssertEqualObjects(nilParent, d.supernode, @"d's parent is messed up");
-
- // Check insert a nil node
- ASDisplayNode *nilNode = nil;
- XCTAssertThrows([parent insertSubnode:nilNode atIndex:0], @"Should not allow insertion of nil node. We will throw in development and deal with it in production");
-
- // Check insert at invalid index
- XCTAssertThrows([parent insertSubnode:d atIndex:NSNotFound], @"Should not allow insertion at invalid index");
- XCTAssertThrows([parent insertSubnode:d atIndex:-1], @"Should not allow insertion at invalid index");
-
- // Should have same state as before
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"Funny business should not corrupt state");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Check reordering existing subnodes with the insert API
- // Move c to front
- [parent insertSubnode:c atIndex:0];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,a,b", @"Move to front when already a subnode");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Move c to middle
- [parent insertSubnode:c atIndex:1];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Move c to middle");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Insert c at the index it's already at
- [parent insertSubnode:c atIndex:1];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Funny business should not corrupt state");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- // Insert c at 0th when it's already in the array
- [parent insertSubnode:c atIndex:2];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b,c", @"Funny business should not corrupt state");
- XCTAssertNodesHaveParent(parent, a, b, c);
- XCTAssertNodesHaveParent(nilParent, d);
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-// This tests our resiliancy to having other views and layers inserted into our view or layer
-- (void)testInsertSubviewAtIndexWithMeddlingViewsAndLayersViewBacked
-{
- ASDisplayNode *parent = [[ASDisplayNode alloc] init];
-
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareViewNamed(d);
- DeclareLayerNamed(e);
-
- [parent layer];
-
- // (a,b)
- [parent addSubnode:a];
- [parent addSubnode:b];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,b", @"Didn't match");
-
- // (a,b) => (a,d,b)
- [parent.view insertSubview:d aboveSubview:a.view];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,d,b", @"Didn't match");
-
- // (a,d,b) => (a,e,d,b)
- [parent.layer insertSublayer:e above:a.layer];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,e,d,b", @"Didn't match");
-
- // (a,e,d,b) => (a,e,d,c,b)
- [parent insertSubnode:c belowSubnode:b];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,e,d,c,b", @"Didn't match");
-
- XCTAssertEqual(4u, parent.subnodes.count, @"Should have the right subnode count");
- XCTAssertEqual(4u, parent.view.subviews.count, @"Should have the right subview count");
- XCTAssertEqual(5u, parent.layer.sublayers.count, @"Should have the right sublayer count");
-
- [e removeFromSuperlayer];
- XCTAssertEqual(4u, parent.layer.sublayers.count, @"Should have the right sublayer count");
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-- (void)testAppleBugInsertSubview
-{
- DeclareViewNamed(parent);
-
- DeclareLayerNamed(aa);
- DeclareLayerNamed(ab);
- DeclareViewNamed(a);
- DeclareLayerNamed(ba);
- DeclareLayerNamed(bb);
- DeclareLayerNamed(bc);
- DeclareLayerNamed(bd);
- DeclareViewNamed(c);
- DeclareViewNamed(d);
- DeclareLayerNamed(ea);
- DeclareLayerNamed(eb);
- DeclareLayerNamed(ec);
-
- [parent.layer addSublayer:aa];
- [parent.layer addSublayer:ab];
- [parent addSubview:a];
- [parent.layer addSublayer:ba];
- [parent.layer addSublayer:bb];
- [parent.layer addSublayer:bc];
- [parent.layer addSublayer:bd];
- [parent addSubview:d];
- [parent.layer addSublayer:ea];
- [parent.layer addSublayer:eb];
- [parent.layer addSublayer:ec];
-
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"aa,ab,a,ba,bb,bc,bd,d,ea,eb,ec", @"Should be in order");
-
- // Should insert at SUBVIEW index 1, right??
- [parent insertSubview:c atIndex:1];
-
- // You would think that this would be true, but instead it inserts it at the SUBLAYER index 1
-// XCTAssertEquals([parent.subviews indexOfObjectIdenticalTo:c], 1u, @"Should have index 1 after insert");
-// XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"aa,ab,a,ba,bb,bc,bd,c,d,ea,eb,ec", @"Should be in order");
-
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"aa,c,ab,a,ba,bb,bc,bd,d,ea,eb,ec", @"Apple has fixed insertSubview:atIndex:. You must update insertSubnode: etc. APIS to accomidate this.");
-}
-
-// This tests our resiliancy to having other views and layers inserted into our view or layer
-- (void)testInsertSubviewAtIndexWithMeddlingView
-{
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareViewNamed(d);
-
- [parent layer];
-
- // (a,b)
- [parent addSubnode:a];
- [parent addSubnode:b];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,b", @"Didn't match");
-
- // (a,b) => (a,d,b)
- [parent.view insertSubview:d aboveSubview:a.view];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,d,b", @"Didn't match");
-
- // (a,d,b) => (a,d,>c<,b)
- [parent insertSubnode:c belowSubnode:b];
- XCTAssertEqualObjects(orderStringFromSublayers(parent.layer), @"a,d,c,b", @"Didn't match");
-
- XCTAssertEqual(4u, parent.subnodes.count, @"Should have the right subnode count");
- XCTAssertEqual(4u, parent.view.subviews.count, @"Should have the right subview count");
- XCTAssertEqual(4u, parent.layer.sublayers.count, @"Should have the right sublayer count");
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-
-- (void)testInsertSubnodeBelowWithView
-{
- [self checkInsertSubnodeBelowWithView:YES layerBacked:NO];
-}
-
-- (void)testInsertSubnodeBelowWithNoView
-{
- [self checkInsertSubnodeBelowWithView:NO layerBacked:NO];
-}
-
-- (void)testInsertSubnodeBelowWithNoLayer
-{
- [self checkInsertSubnodeBelowWithView:NO layerBacked:YES];
-}
-
-- (void)testInsertSubnodeBelowWithLayer
-{
- [self checkInsertSubnodeBelowWithView:YES layerBacked:YES];
-}
-
-
-- (void)checkInsertSubnodeBelowWithView:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
-{
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
-
- for (ASDisplayNode *v in @[parent, a, b, c]) {
- v.layerBacked = isLayerBacked;
- }
-
- [parent addSubnode:b];
-
- if (loaded) {
- [parent layer];
- }
-
- // Shut the type mismatch up
- ASDisplayNode *nilParent = nil;
-
- // (b) => (a, b)
- [parent insertSubnode:a belowSubnode:b];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b", @"Incorrect insertion below");
- XCTAssertNodesHaveParent(parent, a, b);
- XCTAssertNodesHaveParent(nilParent, c);
-
- // (a,b) => (c,a,b)
- [parent insertSubnode:c belowSubnode:a];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,a,b", @"Incorrect insertion below");
- XCTAssertNodesHaveParent(parent, a, b, c);
-
- // Check insertSubnode with no below
- ASDisplayNode *nilNode = nil;
- XCTAssertThrows([parent insertSubnode:b belowSubnode:nilNode], @"Can't insert below a nil");
- // Check nothing was inserted
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,a,b", @"Incorrect insertion below");
-
-
- XCTAssertThrows([parent insertSubnode:nilNode belowSubnode:nilNode], @"Can't insert a nil subnode");
- XCTAssertThrows([parent insertSubnode:nilNode belowSubnode:a], @"Can't insert a nil subnode");
-
- // Check inserting below when you're already in the array
- // (c,a,b) => (a,c,b)
- [parent insertSubnode:c belowSubnode:b];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Incorrect insertion below");
- XCTAssertNodesHaveParent(parent, a, c, b);
-
- // Check what happens when you try to insert a node below itself (should do nothing)
- // (a,c,b) => (a,c,b)
- [parent insertSubnode:c belowSubnode:c];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Incorrect insertion below");
- XCTAssertNodesHaveParent(parent, a, c, b);
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-- (void)testInsertSubnodeAboveWithView
-{
- [self checkInsertSubnodeAboveLoaded:YES layerBacked:NO];
-}
-
-- (void)testInsertSubnodeAboveWithNoView
-{
- [self checkInsertSubnodeAboveLoaded:NO layerBacked:NO];
-}
-
-- (void)testInsertSubnodeAboveWithLayer
-{
- [self checkInsertSubnodeAboveLoaded:YES layerBacked:YES];
-}
-
-- (void)testInsertSubnodeAboveWithNoLayer
-{
- [self checkInsertSubnodeAboveLoaded:NO layerBacked:YES];
-}
-
-
-- (void)checkInsertSubnodeAboveLoaded:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
-{
- DeclareNodeNamed(parent);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
-
- for (ASDisplayNode *n in @[parent, a, b, c]) {
- n.layerBacked = isLayerBacked;
- }
-
- [parent addSubnode:a];
-
- if (loaded) {
- [parent layer];
- }
-
- // Shut the type mismatch up
- ASDisplayNode *nilParent = nil;
-
- // (a) => (a,b)
- [parent insertSubnode:b aboveSubnode:a];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,b", @"Insert subnode above");
- XCTAssertNodesHaveParent(parent, a,b);
- XCTAssertNodesHaveParent(nilParent, c);
-
- // (a,b) => (a,c,b)
- [parent insertSubnode:c aboveSubnode:a];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"After insert c above a");
-
- // Check insertSubnode with invalid parameters throws and doesn't change anything
- // (a,c,b) => (a,c,b)
- ASDisplayNode *nilNode = nil;
- XCTAssertThrows([parent insertSubnode:b aboveSubnode:nilNode], @"Can't insert below a nil");
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Check no monkey business");
-
- XCTAssertThrows([parent insertSubnode:nilNode aboveSubnode:nilNode], @"Can't insert a nil subnode");
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Check no monkey business");
-
- XCTAssertThrows([parent insertSubnode:nilNode aboveSubnode:a], @"Can't insert a nil subnode");
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"a,c,b", @"Check no monkey business");
-
- // Check inserting above when you're already in the array
- // (a,c,b) => (c,b,a)
- [parent insertSubnode:a aboveSubnode:b];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,b,a", @"Check inserting above when you're already in the array");
- XCTAssertNodesHaveParent(parent, a, c, b);
-
- // Check what happens when you try to insert a node above itself (should do nothing)
- // (c,b,a) => (c,b,a)
- [parent insertSubnode:a aboveSubnode:a];
- XCTAssertNodeSubnodeSubviewSublayerOrder(parent, loaded, isLayerBacked, @"c,b,a", @"Insert above self should not change anything");
- XCTAssertNodesHaveParent(parent, a, c, b);
-
- //TODO: assert that things deallocate immediately and don't have latent autoreleases in here
-}
-
-- (void)testRemoveFromViewBackedLoadedSupernode
-{
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- [b addSubnode:a];
- [a view];
- [b view];
- XCTAssertNodesLoaded(a, b);
- XCTAssertEqual(a.supernode, b);
- XCTAssertEqual(a.view.superview, b.view);
-
- [a removeFromSupernode];
- XCTAssertNil(a.supernode);
- XCTAssertNil(a.view.superview);
-}
-
-- (void)testRemoveFromLayerBackedLoadedSupernode
-{
- DeclareNodeNamed(a);
- a.layerBacked = YES;
- DeclareNodeNamed(b);
- b.layerBacked = YES;
- [b addSubnode:a];
- [a layer];
- [b layer];
- XCTAssertNodesLoaded(a, b);
- XCTAssertEqual(a.supernode, b);
- XCTAssertEqual(a.layer.superlayer, b.layer);
-
- [a removeFromSupernode];
- XCTAssertNil(a.supernode);
- XCTAssertNil(a.layer.superlayer);
-}
-
-- (void)testRemoveLayerBackedFromViewBackedLoadedSupernode
-{
- DeclareNodeNamed(a);
- a.layerBacked = YES;
- DeclareNodeNamed(b);
- [b addSubnode:a];
- [a layer];
- [b view];
- XCTAssertNodesLoaded(a, b);
- XCTAssertEqual(a.supernode, b);
- XCTAssertEqual(a.layer.superlayer, b.layer);
-
- [a removeFromSupernode];
- XCTAssertNil(a.supernode);
- XCTAssertNil(a.layer.superlayer);
-}
-
-- (void)testSubnodeAddedBeforeLoadingExternalView
-{
- UIView *view = [[UIDisplayNodeTestView alloc] init];
-
- __block ASDisplayNode *parent = nil;
- __block ASDisplayNode *child = nil;
- [self executeOffThread:^{
- parent = [[ASDisplayNode alloc] initWithViewBlock:^{
- return view;
- }];
- child = [[ASDisplayNode alloc] init];
- [parent addSubnode:child];
- }];
-
- XCTAssertEqual(1, parent.subnodes.count, @"Parent should have 1 subnode");
- XCTAssertEqualObjects(parent, child.supernode, @"Child has the wrong parent");
- XCTAssertEqual(0, view.subviews.count, @"View shouldn't have any subviews");
-
- [parent view];
-
- XCTAssertEqual(1, view.subviews.count, @"View should have 1 subview");
-}
-
-- (void)testSubnodeAddedAfterLoadingExternalView
-{
- UIView *view = [[UIDisplayNodeTestView alloc] init];
- ASDisplayNode *parent = [[ASDisplayNode alloc] initWithViewBlock:^{
- return view;
- }];
-
- [parent view];
-
- ASDisplayNode *child = [[ASDisplayNode alloc] init];
- [parent addSubnode:child];
-
- XCTAssertEqual(1, parent.subnodes.count, @"Parent should have 1 subnode");
- XCTAssertEqualObjects(parent, child.supernode, @"Child has the wrong parent");
- XCTAssertEqual(1, view.subviews.count, @"View should have 1 subview");
-}
-
-- (void)checkBackgroundColorOpaqueRelationshipWithViewLoaded:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layerBacked = isLayerBacked;
-
- if (loaded) {
- // Force load
- [node layer];
- }
-
- XCTAssertTrue(node.opaque, @"Node should start opaque");
- XCTAssertTrue(node.layer.opaque, @"Node should start opaque");
-
- node.backgroundColor = [UIColor clearColor];
-
- // This could be debated, but at the moment we differ from UIView's behavior to change the other property in response
- XCTAssertTrue(node.opaque, @"Set background color should not have made this not opaque");
- XCTAssertTrue(node.layer.opaque, @"Set background color should not have made this not opaque");
-
- [node layer];
-
- XCTAssertTrue(node.opaque, @"Set background color should not have made this not opaque");
- XCTAssertTrue(node.layer.opaque, @"Set background color should not have made this not opaque");
-}
-
-- (void)testBackgroundColorOpaqueRelationshipView
-{
- [self checkBackgroundColorOpaqueRelationshipWithViewLoaded:YES layerBacked:NO];
-}
-
-- (void)testBackgroundColorOpaqueRelationshipLayer
-{
- [self checkBackgroundColorOpaqueRelationshipWithViewLoaded:YES layerBacked:YES];
-}
-
-- (void)testBackgroundColorOpaqueRelationshipNoView
-{
- [self checkBackgroundColorOpaqueRelationshipWithViewLoaded:NO layerBacked:NO];
-}
-
-- (void)testBackgroundColorOpaqueRelationshipNoLayer
-{
- [self checkBackgroundColorOpaqueRelationshipWithViewLoaded:NO layerBacked:YES];
-}
-
-// Check that nodes who have no cell node (no range controller)
-// do get their `preload` called, and they do report
-// the preload interface state.
-- (void)testInterfaceStateForNonCellNode
-{
- ASTestWindow *window = [ASTestWindow new];
- ASTestDisplayNode *node = [ASTestDisplayNode new];
- XCTAssert(node.interfaceState == ASInterfaceStateNone);
- XCTAssert(!node.hasPreloaded);
-
- [window addSubview:node.view];
- XCTAssert(node.hasPreloaded);
- XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy);
-
- [node.view removeFromSuperview];
- // We don't want to call -didExitPreloadState on nodes that aren't being managed by a range controller.
- // Otherwise we get flashing behavior from normal UIKit manipulations like navigation controller push / pop.
- // Still, the interfaceState should be None to reflect the current state of the node.
- // We just don't proactively clear contents or fetched data for this state transition.
- XCTAssert(node.hasPreloaded);
- XCTAssert(node.interfaceState == ASInterfaceStateNone);
-}
-
-// Check that nodes who have no cell node (no range controller)
-// do get their `preload` called, and they do report
-// the preload interface state.
-- (void)testInterfaceStateForCellNode
-{
- ASCellNode *cellNode = [ASCellNode new];
- ASTestDisplayNode *node = [ASTestDisplayNode new];
- XCTAssert(node.interfaceState == ASInterfaceStateNone);
- XCTAssert(!node.hasPreloaded);
-
- // Simulate range handler updating cell node.
- [cellNode addSubnode:node];
- [cellNode enterInterfaceState:ASInterfaceStatePreload];
- XCTAssert(node.hasPreloaded);
- XCTAssert(node.interfaceState == ASInterfaceStatePreload);
-
- // If the node goes into a view it should not adopt the `InHierarchy` state.
- ASTestWindow *window = [ASTestWindow new];
- [window addSubview:cellNode.view];
- XCTAssert(node.hasPreloaded);
- XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy);
-}
-
-- (void)testSetNeedsPreloadImmediateState
-{
- ASCellNode *cellNode = [ASCellNode new];
- ASTestDisplayNode *node = [ASTestDisplayNode new];
- [cellNode addSubnode:node];
- [cellNode enterInterfaceState:ASInterfaceStatePreload];
- node.hasPreloaded = NO;
- [cellNode setNeedsPreload];
- XCTAssert(node.hasPreloaded);
-}
-
-- (void)testPreloadExitingAndEnteringRange
-{
- ASCellNode *cellNode = [ASCellNode new];
- ASTestDisplayNode *node = [ASTestDisplayNode new];
- [cellNode addSubnode:node];
- [cellNode setHierarchyState:ASHierarchyStateRangeManaged];
-
- // Simulate enter range, preload, exit range
- [cellNode enterInterfaceState:ASInterfaceStatePreload];
- [cellNode exitInterfaceState:ASInterfaceStatePreload];
- node.hasPreloaded = NO;
- [cellNode enterInterfaceState:ASInterfaceStatePreload];
-
- XCTAssert(node.hasPreloaded);
-}
-
-- (void)testInitWithViewClass
-{
- ASDisplayNode *scrollNode = [[ASDisplayNode alloc] initWithViewClass:[UIScrollView class]];
-
- XCTAssertFalse(scrollNode.isLayerBacked, @"Can't be layer backed");
- XCTAssertFalse(scrollNode.nodeLoaded, @"Shouldn't have a view yet");
-
- scrollNode.frame = CGRectMake(12, 52, 100, 53);
- scrollNode.alpha = 0.5;
-
- XCTAssertTrue([scrollNode.view isKindOfClass:[UIScrollView class]], @"scrollview should load as expected");
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(12, 52, 100, 53), scrollNode.frame), @"Should have set the frame on the scroll node");
- XCTAssertEqual(0.5f, scrollNode.alpha, @"Alpha not working");
-}
-
-- (void)testInitWithLayerClass
-{
- ASDisplayNode *transformNode = [[ASDisplayNode alloc] initWithLayerClass:[CATransformLayer class]];
-
- XCTAssertTrue(transformNode.isLayerBacked, @"Created with layer class => should be layer-backed by default");
- XCTAssertFalse(transformNode.nodeLoaded, @"Shouldn't have a view yet");
-
- transformNode.frame = CGRectMake(12, 52, 100, 53);
- transformNode.alpha = 0.5;
-
- XCTAssertTrue([transformNode.layer isKindOfClass:[CATransformLayer class]], @"scrollview should load as expected");
- XCTAssertTrue(CGRectEqualToRect(CGRectMake(12, 52, 100, 53), transformNode.frame), @"Should have set the frame on the scroll node");
- XCTAssertEqual(0.5f, transformNode.alpha, @"Alpha not working");
-}
-
-static bool stringContainsPointer(NSString *description, id p) {
- return [description rangeOfString:[NSString stringWithFormat:@"%p", p]].location != NSNotFound;
-}
-
-- (void)testDebugDescription
-{
- // View node has subnodes. Make sure all of the nodes are included in the description
- ASDisplayNode *parent = [[ASDisplayNode alloc] init];
-
- ASDisplayNode *a = [[ASDisplayNode alloc] init];
- a.layerBacked = YES;
- ASDisplayNode *b = [[ASDisplayNode alloc] init];
- b.layerBacked = YES;
- b.frame = CGRectMake(0, 0, 100, 123);
- ASDisplayNode *c = [[ASDisplayNode alloc] init];
-
- for (ASDisplayNode *child in @[a, b, c]) {
- [parent addSubnode:child];
- }
-
- NSString *nodeDescription = [parent displayNodeRecursiveDescription];
-
- // Make sure [parent recursiveDescription] contains a, b, and c's pointer string
- XCTAssertTrue(stringContainsPointer(nodeDescription, a), @"Layer backed node not present in [parent displayNodeRecursiveDescription]");
- XCTAssertTrue(stringContainsPointer(nodeDescription, b), @"Layer-backed node not present in [parent displayNodeRecursiveDescription]");
- XCTAssertTrue(stringContainsPointer(nodeDescription, c), @"View-backed node not present in [parent displayNodeRecursiveDescription]");
-
- NSString *viewDescription = [parent.view valueForKey:@"recursiveDescription"];
-
- // Make sure string contains a, b, and c's pointer string
- XCTAssertTrue(stringContainsPointer(viewDescription, a), @"Layer backed node not present");
- XCTAssertTrue(stringContainsPointer(viewDescription, b), @"Layer-backed node not present");
- XCTAssertTrue(stringContainsPointer(viewDescription, c), @"View-backed node not present");
-
- // Make sure layer names have display node in description
- XCTAssertTrue(stringContainsPointer([a.layer debugDescription], a), @"Layer backed node not present");
- XCTAssertTrue(stringContainsPointer([b.layer debugDescription], b), @"Layer-backed node not present");
-}
-
-- (void)checkNameInDescriptionIsLayerBacked:(BOOL)isLayerBacked
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layerBacked = isLayerBacked;
-
- XCTAssertFalse([node.description containsString:@"debugName"], @"Shouldn't reference 'debugName' in description");
- node.debugName = @"big troll eater name";
-
- XCTAssertTrue([node.description containsString:node.debugName], @"debugName didn't end up in description");
- [node layer];
- XCTAssertTrue([node.description containsString:node.debugName], @"debugName didn't end up in description");
-}
-
-- (void)testNameInDescriptionLayer
-{
- [self checkNameInDescriptionIsLayerBacked:YES];
-}
-
-- (void)testNameInDescriptionView
-{
- [self checkNameInDescriptionIsLayerBacked:NO];
-}
-
-- (void)testBounds
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.bounds = CGRectMake(1, 2, 3, 4);
- node.frame = CGRectMake(5, 6, 7, 8);
-
- XCTAssert(node.bounds.origin.x == 1, @"Wrong ASDisplayNode.bounds.origin.x");
- XCTAssert(node.bounds.origin.y == 2, @"Wrong ASDisplayNode.bounds.origin.y");
- XCTAssert(node.bounds.size.width == 7, @"Wrong ASDisplayNode.bounds.size.width");
- XCTAssert(node.bounds.size.height == 8, @"Wrong ASDisplayNode.bounds.size.height");
-}
-
-- (void)testDidEnterDisplayIsCalledWhenNodesEnterDisplayRange
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
-
- [node recursivelySetInterfaceState:ASInterfaceStateDisplay];
-
- XCTAssert([node displayRangeStateChangedToYES]);
-}
-
-- (void)testDidExitDisplayIsCalledWhenNodesExitDisplayRange
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
-
- [node recursivelySetInterfaceState:ASInterfaceStateDisplay];
- [node recursivelySetInterfaceState:ASInterfaceStatePreload];
-
- XCTAssert([node displayRangeStateChangedToNO]);
-}
-
-- (void)testDidEnterPreloadIsCalledWhenNodesEnterPreloadRange
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
-
- [node recursivelySetInterfaceState:ASInterfaceStatePreload];
-
- XCTAssert([node preloadStateChangedToYES]);
-}
-
-- (void)testDidExitPreloadIsCalledWhenNodesExitPreloadRange
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- [node setHierarchyState:ASHierarchyStateRangeManaged];
-
- [node recursivelySetInterfaceState:ASInterfaceStatePreload];
- [node recursivelySetInterfaceState:ASInterfaceStateDisplay];
-
- XCTAssert([node preloadStateChangedToNO]);
-}
-
-
-- (void)testThatNodeGetsRenderedIfItGoesFromZeroSizeToRealSizeButOnlyOnce
-{
- NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo-square"
- ofType:@"png" inDirectory:@"TestResources"];
- UIImage *image = [UIImage imageWithContentsOfFile:path];
- ASImageNode *node = [[ASImageNode alloc] init];
- node.image = image;
-
- // When rendered at zero-size, we get no contents
- XCTAssert(CGSizeEqualToSize(node.bounds.size, CGSizeZero));
- [node recursivelyEnsureDisplaySynchronously:YES];
- XCTAssertNil(node.contents);
-
- // When size becomes positive, we got some new contents
- node.bounds = CGRectMake(0, 0, 100, 100);
- [node recursivelyEnsureDisplaySynchronously:YES];
- id contentsAfterRedisplay = node.contents;
- XCTAssertNotNil(contentsAfterRedisplay);
-
- // When size changes again, we do not get new contents
- node.bounds = CGRectMake(0, 0, 1000, 1000);
- [node recursivelyEnsureDisplaySynchronously:YES];
- XCTAssertEqual(contentsAfterRedisplay, node.contents);
-}
-
-// Underlying issue for: https://github.com/facebook/AsyncDisplayKit/issues/2205
-- (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenContainerEntersHierarchy
-{
- ASDisplayNode *supernode = [[ASTestDisplayNode alloc] init];
- [supernode enableSubtreeRasterization];
- ASDisplayNode *subnode = [[ASTestDisplayNode alloc] init];
- ASSetDebugNames(supernode, subnode);
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- [supernode addSubnode:subnode];
- [window addSubnode:supernode];
- [window makeKeyAndVisible];
- XCTAssertTrue(ASHierarchyStateIncludesRasterized(subnode.hierarchyState));
- XCTAssertTrue(subnode.isVisible);
- [supernode.view removeFromSuperview];
- XCTAssertTrue(ASHierarchyStateIncludesRasterized(subnode.hierarchyState));
- XCTAssertFalse(subnode.isVisible);
-}
-
-// Underlying issue for: https://github.com/facebook/AsyncDisplayKit/issues/2205
-- (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenAddedToContainerThatIsInHierarchy
-{
- ASDisplayNode *supernode = [[ASTestDisplayNode alloc] init];
- [supernode enableSubtreeRasterization];
- ASDisplayNode *subnode = [[ASTestDisplayNode alloc] init];
- ASSetDebugNames(supernode, subnode);
-
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- [window addSubnode:supernode];
- [window makeKeyAndVisible];
- [supernode addSubnode:subnode];
- XCTAssertTrue(ASHierarchyStateIncludesRasterized(subnode.hierarchyState));
- XCTAssertTrue(subnode.isVisible);
- [subnode removeFromSupernode];
- XCTAssertFalse(ASHierarchyStateIncludesRasterized(subnode.hierarchyState));
- XCTAssertFalse(subnode.isVisible);
-}
-
-- (void)testThatRasterizingWrapperNodesIsNotAllowed
-{
- ASDisplayNode *rasterizedSupernode = [[ASDisplayNode alloc] init];
- [rasterizedSupernode enableSubtreeRasterization];
- ASDisplayNode *subnode = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull{
- return [[UIView alloc] init];
- }];
- ASSetDebugNames(rasterizedSupernode, subnode);
- XCTAssertThrows([rasterizedSupernode addSubnode:subnode]);
-}
-
-- (void)testThatSubnodesGetDisplayUpdatesIfRasterized
-{
- ASTestDisplayNode *supernode = [[ASTestDisplayNode alloc] init];
- supernode.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
- [supernode enableSubtreeRasterization];
-
- ASTestDisplayNode *subnode = [[ASTestDisplayNode alloc] init];
- ASTestDisplayNode *subSubnode = [[ASTestDisplayNode alloc] init];
-
- ASSetDebugNames(supernode, subnode);
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- [subnode addSubnode:subSubnode];
- [supernode addSubnode:subnode];
- [window addSubnode:supernode];
- [window makeKeyAndVisible];
-
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (subnode.didDisplayCount == 1);
- }));
-
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (subSubnode.didDisplayCount == 1);
- }));
-
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (subnode.displayWillStartCount == 1);
- }));
-
- XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{
- return (subSubnode.displayWillStartCount == 1);
- }));
-}
-
-// Underlying issue for: https://github.com/facebook/AsyncDisplayKit/issues/2011
-- (void)testThatLayerBackedSubnodesAreMarkedInvisibleBeforeDeallocWhenSupernodesViewIsRemovedFromHierarchyWhileBeingRetained
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
-
- NS_VALID_UNTIL_END_OF_SCOPE UIView *nodeView = nil;
- {
- NS_VALID_UNTIL_END_OF_SCOPE ASDisplayNode *node = [[ASDisplayNode alloc] init];
- nodeView = node.view;
- node.debugName = @"Node";
-
- NS_VALID_UNTIL_END_OF_SCOPE ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
- subnode.layerBacked = YES;
- [node addSubnode:subnode];
- subnode.debugName = @"Subnode";
-
- [window addSubview:nodeView];
- }
-
- // nodeView must continue to be retained across this call, but the nodes must not.
- XCTAssertNoThrow([nodeView removeFromSuperview]);
-}
-
-// Running on main thread
-// Cause retain count of node to fall to zero synchronously on a background thread (pausing main thread)
-// ASDealloc2MainObject queues actual call to -dealloc to occur on the main thread
-// Continue execution on main, before the dealloc can run, to dealloc the host view
-// Node is in an invalid state (about to dealloc, not valid to retain) but accesses to sublayer delegates
-// causes attempted retain — unless weak variable works correctly
-- (void)testThatLayerDelegateDoesntDangleAndCauseCrash
-{
- NS_VALID_UNTIL_END_OF_SCOPE UIView *host = [[UIView alloc] init];
-
- __block NS_VALID_UNTIL_END_OF_SCOPE ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layerBacked = YES;
-
- [host addSubnode:node];
- [self executeOffThread:^{
- node = nil;
- }];
- host = nil; // <- Would crash here, when UIView accesses its sublayers' delegates in -dealloc.
-}
-
-- (void)testThatSubnodeGetsInterfaceStateSetIfRasterized
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- node.debugName = @"Node";
- [node enableSubtreeRasterization];
-
- ASTestDisplayNode *subnode = [[ASTestDisplayNode alloc] init];
- subnode.debugName = @"Subnode";
- [node addSubnode:subnode];
-
- [node view]; // Node needs to be loaded
-
- [node enterInterfaceState:ASInterfaceStatePreload];
-
- XCTAssertTrue((node.interfaceState & ASInterfaceStatePreload) == ASInterfaceStatePreload);
- XCTAssertTrue((subnode.interfaceState & ASInterfaceStatePreload) == ASInterfaceStatePreload);
- XCTAssertTrue(node.hasPreloaded);
- XCTAssertTrue(subnode.hasPreloaded);
-}
-
-// FIXME
-// Supernode is measured, subnode isnt, transition starts, UIKit does a layout pass before measurement finishes
-- (void)testThatItsSafeToAutomeasureANodeMidTransition
-{
- ASDisplayNode *supernode = [[ASDisplayNode alloc] init];
- [supernode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))];
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.bounds = CGRectMake(0, 0, 50, 50);
- [supernode addSubnode:node];
-
- XCTAssertNil(node.calculatedLayout);
- XCTAssertTrue(node.layer.needsLayout);
-
- [supernode transitionLayoutWithAnimation:NO shouldMeasureAsync:YES measurementCompletion:nil];
-
- XCTAssertNoThrow([node.view layoutIfNeeded]);
-}
-
-- (void)testThatOnDidLoadThrowsIfCalledOnLoadedOffMain
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- [node view];
- [self executeOffThread:^{
- XCTAssertThrows([node onDidLoad:^(ASDisplayNode * _Nonnull node) { }]);
- }];
-}
-
-- (void)testThatOnDidLoadWorks
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- NSMutableArray *calls = [NSMutableArray array];
- [node onDidLoad:^(ASTestDisplayNode * _Nonnull node) {
- [calls addObject:@0];
- }];
- [node onDidLoad:^(ASTestDisplayNode * _Nonnull node) {
- [calls addObject:@1];
- }];
- [node onDidLoad:^(ASTestDisplayNode * _Nonnull node) {
- [calls addObject:@2];
- }];
- [node view];
- NSArray *expected = @[ @0, @1, @2 ];
- XCTAssertEqualObjects(calls, expected);
-}
-
-- (void)testSettingPropertiesViaStyllableProtocol
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- id returnedNode =
- [node styledWithBlock:^(ASLayoutElementStyle * _Nonnull style) {
- style.width = ASDimensionMake(100);
- style.flexGrow = 1.0;
- style.flexShrink = 1.0;
- }];
-
- XCTAssertEqualObjects(node, returnedNode);
- ASXCTAssertEqualDimensions(node.style.width, ASDimensionMake(100));
- XCTAssertEqual(node.style.flexGrow, 1.0, @"flexGrow should have have the value 1.0");
- XCTAssertEqual(node.style.flexShrink, 1.0, @"flexShrink should have have the value 1.0");
-}
-
-- (void)testSubnodesFastEnumeration
-{
- DeclareNodeNamed(parentNode);
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareViewNamed(d);
-
- NSArray *subnodes = @[a, b, c, d];
- for (ASDisplayNode *node in subnodes) {
- [parentNode addSubnode:node];
- }
-
- NSInteger i = 0;
- for (ASDisplayNode *subnode in parentNode.subnodes) {
- XCTAssertEqualObjects(subnode, subnodes[i]);
- i++;
- }
-}
-
-- (void)testThatHavingTheSameNodeTwiceInALayoutSpecCausesExceptionOnLayoutCalculation
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
- node.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode *node, ASSizeRange constrainedSize) {
- return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:[ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:subnode] overlay:subnode];
- };
- XCTAssertThrowsSpecificNamed([node calculateLayoutThatFits:ASSizeRangeMake(CGSizeMake(100, 100))], NSException, NSInternalInconsistencyException);
-}
-
-- (void)testThatStackSpecOrdersSubnodesCorrectlyRandomness
-{
- // This test ensures that the z-order of nodes matches the stack spec, including after several random relayouts / transitions.
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
-
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareNodeNamed(d);
- DeclareNodeNamed(e);
- DeclareNodeNamed(f);
- DeclareNodeNamed(g);
- DeclareNodeNamed(h);
- DeclareNodeNamed(i);
- DeclareNodeNamed(j);
-
- NSMutableArray *allNodes = [@[a, b, c, d, e, f, g, h, i, j] mutableCopy];
- NSArray *testPrevious = @[];
- NSArray __block *testPending = @[];
-
- int len1 = 1 + arc4random_uniform(9);
- for (NSUInteger n = 0; n < len1; n++) { // shuffle and add
- [allNodes exchangeObjectAtIndex:n withObjectAtIndex:n + arc4random_uniform(10 - (uint32_t) n)];
- testPrevious = [testPrevious arrayByAddingObject:allNodes[n]];
- }
-
- __block NSUInteger testCount = 0;
- node.layoutSpecBlock = ^(ASDisplayNode *node, ASSizeRange size) {
- ASStackLayoutSpec *stack = [ASStackLayoutSpec verticalStackLayoutSpec];
-
- if (testCount++ == 0) {
- stack.children = testPrevious;
- }
- else {
- testPending = @[];
- int len2 = 1 + arc4random_uniform(9);
- for (NSUInteger n = 0; n < len2; n++) { // shuffle and add
- [allNodes exchangeObjectAtIndex:n withObjectAtIndex:n + arc4random_uniform(10 - (uint32_t) n)];
- testPending = [testPending arrayByAddingObject:allNodes[n]];
- }
- stack.children = testPending;
- }
-
- return stack;
- };
-
- ASDisplayNodeSizeToFitSize(node, CGSizeMake(100, 100));
- [node.view layoutIfNeeded];
-
- // Because automaticallyManagesSubnodes is used, the subnodes array is constructed from the layout spec's children.
- NSString *expected = [[testPrevious valueForKey:@"debugName"] componentsJoinedByString:@","];
- XCTAssert([node.subnodes isEqualToArray:testPrevious], @"subnodes: %@, array: %@", node.subnodes, testPrevious);
- XCTAssertNodeSubnodeSubviewSublayerOrder(node, YES /* isLoaded */, NO /* isLayerBacked */,
- expected, @"Initial order");
-
- for (NSUInteger n = 0; n < 25; n++) {
- [node invalidateCalculatedLayout];
- [node.view setNeedsLayout];
- [node.view layoutIfNeeded];
-
-
- XCTAssert([node.subnodes isEqualToArray:testPending], @"subnodes: %@, array: %@", node.subnodes, testPending);
- expected = [[testPending valueForKey:@"debugName"] componentsJoinedByString:@","];
-
- XCTAssertEqualObjects(orderStringFromSubnodes(node), expected, @"Incorrect node order for Random order #%ld", (unsigned long) n);
- XCTAssertEqualObjects(orderStringFromSubviews(node.view), expected, @"Incorrect subviews for Random order #%ld", (unsigned long) n);
- XCTAssertEqualObjects(orderStringFromSublayers(node.layer), expected, @"Incorrect sublayers for Random order #%ld", (unsigned long) n);
- }
-}
-
-- (void)testThatStackSpecOrdersSubnodesCorrectly
-{
- // This test ensures that the z-order of nodes matches the stack spec, including after relayout / transition.
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
-
- DeclareNodeNamed(a);
- DeclareNodeNamed(b);
- DeclareNodeNamed(c);
- DeclareNodeNamed(d);
- DeclareNodeNamed(e);
-
- NSArray *nodesForwardOrder = @[a, b, c, d];
- NSArray *nodesReverseOrder = @[d, c, b, a];
- NSArray *addAndMoveOrder = @[a, b, e, d, c];
- __block BOOL flipItemOrder = NO;
-
- __block NSUInteger testCount = 0;
- node.layoutSpecBlock = ^(ASDisplayNode *node, ASSizeRange size) {
- ASStackLayoutSpec *stack = [ASStackLayoutSpec verticalStackLayoutSpec];
- switch(testCount) {
- case 0:
- stack.children = nodesForwardOrder; break;
- case 1:
- stack.children = nodesReverseOrder; break;
- case 2:
- default:
- stack.children = addAndMoveOrder; break;
- }
- testCount++;
- return stack;
- };
-
- ASDisplayNodeSizeToFitSize(node, CGSizeMake(100, 100));
- [node.view layoutIfNeeded];
-
- // Because automaticallyManagesSubnodes is used, the subnodes array is constructed from the layout spec's children.
- XCTAssert([node.subnodes isEqualToArray:nodesForwardOrder], @"subnodes: %@, array: %@", node.subnodes, nodesForwardOrder);
- XCTAssertNodeSubnodeSubviewSublayerOrder(node, YES /* isLoaded */, NO /* isLayerBacked */,
- @"a,b,c,d", @"Forward order");
-
- flipItemOrder = YES;
- [node invalidateCalculatedLayout];
- [node.view setNeedsLayout];
- [node.view layoutIfNeeded];
-
- // In this case, it's critical that the items are in the new order so that event handling and apparent z-position are correct.
- // FIXME: The reversal case is not currently passing.
- XCTAssert([node.subnodes isEqualToArray:nodesReverseOrder], @"subnodes: %@, array: %@", node.subnodes, nodesReverseOrder);
- XCTAssertNodeSubnodeSubviewSublayerOrder(node, YES /* isLoaded */, NO /* isLayerBacked */,
- @"d,c,b,a", @"Reverse order");
-
- [node invalidateCalculatedLayout];
- [node.view setNeedsLayout];
- [node.view layoutIfNeeded];
- XCTAssert([node.subnodes isEqualToArray:addAndMoveOrder], @"subnodes: %@, array: %@", node.subnodes, addAndMoveOrder);
- XCTAssertNodeSubnodeSubviewSublayerOrder(node, YES /* isLoaded */, NO /* isLayerBacked */,
- @"a,b,e,d,c", @"AddAndMove order");
-
-}
-
-- (void)testThatOverlaySpecOrdersSubnodesCorrectly
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
- ASDisplayNode *underlay = [[ASDisplayNode alloc] init];
- underlay.debugName = @"underlay";
- ASDisplayNode *overlay = [[ASDisplayNode alloc] init];
- overlay.debugName = @"overlay";
- node.layoutSpecBlock = ^(ASDisplayNode *node, ASSizeRange size) {
- // The inset spec here is crucial. If the nodes themselves are children, it passed before the fix.
- return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:[ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:underlay] overlay:overlay];
- };
-
- ASDisplayNodeSizeToFitSize(node, CGSizeMake(100, 100));
- [node.view layoutIfNeeded];
-
- NSInteger underlayIndex = [node.subnodes indexOfObjectIdenticalTo:underlay];
- NSInteger overlayIndex = [node.subnodes indexOfObjectIdenticalTo:overlay];
- XCTAssertLessThan(underlayIndex, overlayIndex);
-}
-
-- (void)testThatBackgroundLayoutSpecOrdersSubnodesCorrectly
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
- ASDisplayNode *underlay = [[ASDisplayNode alloc] init];
- underlay.debugName = @"underlay";
- ASDisplayNode *overlay = [[ASDisplayNode alloc] init];
- overlay.debugName = @"overlay";
- node.layoutSpecBlock = ^(ASDisplayNode *node, ASSizeRange size) {
- // The inset spec here is crucial. If the nodes themselves are children, it passed before the fix.
- return [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:overlay background:[ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:underlay]];
- };
-
- ASDisplayNodeSizeToFitSize(node, CGSizeMake(100, 100));
- [node.view layoutIfNeeded];
-
- NSInteger underlayIndex = [node.subnodes indexOfObjectIdenticalTo:underlay];
- NSInteger overlayIndex = [node.subnodes indexOfObjectIdenticalTo:overlay];
- XCTAssertLessThan(underlayIndex, overlayIndex);
-}
-
-- (void)testThatConvertPointGoesToWindowWhenPassedNil
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.frame = CGRectMake(10, 10, 10, 10);
- [window addSubnode:node];
- CGPoint expectedOrigin = CGPointMake(10, 10);
- ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
-}
-
-- (void)testThatConvertPointGoesToWindowWhenPassedNil_layerBacked
-{
- UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layerBacked = YES;
- node.frame = CGRectMake(10, 10, 10, 10);
- [window addSubnode:node];
- CGPoint expectedOrigin = CGPointMake(10, 10);
- ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
-}
-
-- (void)testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- UIViewController *vc = [[UIViewController alloc] init];
- [vc.view addSubnode:node];
- dispatch_group_t g = dispatch_group_create();
- __block NSString *debugDescription;
- dispatch_group_async(g, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
- debugDescription = [node debugDescription];
- });
- dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
- // Ensure the debug description contains the VC string.
- // Have to split into two lines because XCTAssert macro can't handle the stringWithFormat:.
- BOOL hasVC = [debugDescription containsString:[NSString stringWithFormat:@"%p", vc]];
- XCTAssert(hasVC);
-}
-
-- (void)testThatSubnodeSafeAreaInsetsAreCalculatedCorrectly
-{
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
-
- rootNode.automaticallyManagesSubnodes = YES;
- rootNode.layoutSpecBlock = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(1, 2, 3, 4) child:subnode];
- };
-
- ASTestViewController *viewController = [[ASTestViewController alloc] initWithNode:rootNode];
- viewController.additionalSafeAreaInsets = UIEdgeInsetsMake(10, 10, 10, 10);
-
- // It looks like iOS 11 suppresses safeAreaInsets calculation for the views that are not on screen.
- UIWindow *window = [[UIWindow alloc] init];
- window.rootViewController = viewController;
- [window setHidden:NO];
- [window layoutIfNeeded];
-
- UIEdgeInsets expectedRootNodeSafeArea = UIEdgeInsetsMake(10, 10, 10, 10);
- UIEdgeInsets expectedSubnodeSafeArea = UIEdgeInsetsMake(9, 8, 7, 6);
-
- UIEdgeInsets windowSafeArea = UIEdgeInsetsZero;
- if (AS_AVAILABLE_IOS(11.0)) {
- windowSafeArea = window.safeAreaInsets;
- }
-
- expectedRootNodeSafeArea = ASConcatInsets(expectedRootNodeSafeArea, windowSafeArea);
- expectedSubnodeSafeArea = ASConcatInsets(expectedSubnodeSafeArea, windowSafeArea);
-
- XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(expectedRootNodeSafeArea, rootNode.safeAreaInsets),
- @"expected rootNode.safeAreaInsets to be %@ but got %@ (window.safeAreaInsets %@)",
- NSStringFromUIEdgeInsets(expectedRootNodeSafeArea),
- NSStringFromUIEdgeInsets(rootNode.safeAreaInsets),
- NSStringFromUIEdgeInsets(windowSafeArea));
- XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(expectedSubnodeSafeArea, subnode.safeAreaInsets),
- @"expected subnode.safeAreaInsets to be %@ but got %@ (window.safeAreaInsets %@)",
- NSStringFromUIEdgeInsets(expectedSubnodeSafeArea),
- NSStringFromUIEdgeInsets(subnode.safeAreaInsets),
- NSStringFromUIEdgeInsets(windowSafeArea));
-
- [window setHidden:YES];
-}
-
-- (void)testScreenScale
-{
- XCTAssertEqual(ASScreenScale(), UIScreen.mainScreen.scale);
-}
-
-- (void)testThatIfViewClassIsOverwrittenItsSynchronous
-{
- ASSynchronousTestDisplayNodeViaViewClass *node = [[ASSynchronousTestDisplayNodeViaViewClass alloc] init];
- XCTAssertTrue([node isSynchronous], @"Node should be synchronous if viewClass is ovewritten and not a subclass of _ASDisplayView");
-}
-
-- (void)testThatIfLayerClassIsOverwrittenItsSynchronous
-{
- ASSynchronousTestDisplayNodeViaLayerClass *node = [[ASSynchronousTestDisplayNodeViaLayerClass alloc] init];
- XCTAssertTrue([node isSynchronous], @"Node should be synchronous if viewClass is ovewritten and not a subclass of _ASDisplayView");
-}
-
-- (void)testCornerRoundingTypeClippingRoundedCornersIsUsingASDisplayNodeCornerLayerDelegate
-{
- ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init];
- node.cornerRoundingType = ASCornerRoundingTypeClipping;
- node.cornerRadius = 10.0;
- auto l = node.clipCornerLayers;
- for (int i = 0; i < NUM_CLIP_CORNER_LAYERS; i++) {
- CALayer *cornerLayer = (*l)[i];
- XCTAssertTrue([cornerLayer.delegate isKindOfClass:[ASDisplayNodeCornerLayerDelegate class]], @"");
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.h b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.h
deleted file mode 100644
index 4e884f4428..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// ASDisplayNodeTestsHelper.h
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-@class ASCATransactionQueue, ASDisplayNode;
-
-typedef BOOL (^as_condition_block_t)(void);
-
-AS_EXTERN BOOL ASDisplayNodeRunRunLoopUntilBlockIsTrue(as_condition_block_t block);
-
-AS_EXTERN void ASDisplayNodeSizeToFitSize(ASDisplayNode *node, CGSize size);
-AS_EXTERN void ASDisplayNodeSizeToFitSizeRange(ASDisplayNode *node, ASSizeRange sizeRange);
-AS_EXTERN void ASCATransactionQueueWait(ASCATransactionQueue *q); // nil means shared queue
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.mm
deleted file mode 100644
index ae20549117..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayNodeTestsHelper.mm
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// ASDisplayNodeTestsHelper.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASDisplayNodeTestsHelper.h"
-#import
-#import
-#import
-
-#import
-
-#import
-
-// Poll the condition 1000 times a second.
-static CFTimeInterval kSingleRunLoopTimeout = 0.001;
-
-// Time out after 30 seconds.
-static CFTimeInterval kTimeoutInterval = 30.0f;
-
-BOOL ASDisplayNodeRunRunLoopUntilBlockIsTrue(as_condition_block_t block)
-{
- CFTimeInterval timeoutDate = CACurrentMediaTime() + kTimeoutInterval;
- BOOL passed = NO;
- while (true) {
- OSMemoryBarrier();
- passed = block();
- OSMemoryBarrier();
- if (passed) {
- break;
- }
- CFTimeInterval now = CACurrentMediaTime();
- if (now > timeoutDate) {
- break;
- }
- // Run until the poll timeout or until timeoutDate, whichever is first.
- CFTimeInterval runLoopTimeout = MIN(kSingleRunLoopTimeout, timeoutDate - now);
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, runLoopTimeout, true);
- }
- return passed;
-}
-
-void ASDisplayNodeSizeToFitSize(ASDisplayNode *node, CGSize size)
-{
- CGSize sizeThatFits = [node layoutThatFits:ASSizeRangeMake(size)].size;
- node.bounds = (CGRect){.origin = CGPointZero, .size = sizeThatFits};
-}
-
-void ASDisplayNodeSizeToFitSizeRange(ASDisplayNode *node, ASSizeRange sizeRange)
-{
- CGSize sizeThatFits = [node layoutThatFits:sizeRange].size;
- node.bounds = (CGRect){.origin = CGPointZero, .size = sizeThatFits};
-}
-
-void ASCATransactionQueueWait(ASCATransactionQueue *q)
-{
- if (!q) { q = ASCATransactionQueueGet(); }
- NSDate *date = [NSDate dateWithTimeIntervalSinceNow:1];
- BOOL whileResult = YES;
- while ([date timeIntervalSinceNow] > 0 &&
- (whileResult = ![q isEmpty])) {
- [[NSRunLoop currentRunLoop] runUntilDate:
- [NSDate dateWithTimeIntervalSinceNow:0.01]];
- }
-}
diff --git a/submodules/AsyncDisplayKit/Tests/ASDisplayViewAccessibilityTests.mm b/submodules/AsyncDisplayKit/Tests/ASDisplayViewAccessibilityTests.mm
deleted file mode 100644
index bbc28cf0b3..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASDisplayViewAccessibilityTests.mm
+++ /dev/null
@@ -1,303 +0,0 @@
-//
-// ASDisplayViewAccessibilityTests.mm
-// Texture
-//
-// Copyright (c) 2018-present, Pinterest, Inc. All rights reserved.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-#import
-#import
-#import
-#import
-
-@interface ASDisplayViewAccessibilityTests : XCTestCase
-@end
-
-@implementation ASDisplayViewAccessibilityTests
-
-- (void)setUp
-{
- ASConfiguration *config = [[ASConfiguration alloc] initWithDictionary:nil];
- config.experimentalFeatures = ASExperimentalDisableAccessibilityCache;
- [ASConfigurationManager test_resetWithConfiguration:config];
-}
-
-- (void)testAccessibilityElementsAccessors
-{
- // Setup nodes with accessibility info
- ASDisplayNode *node = nil;
- ASDisplayNode *subnode = nil;
- node = [[ASDisplayNode alloc] init];
- subnode = [[ASDisplayNode alloc] init];
- NSString *label = @"foo";
- subnode.isAccessibilityElement = YES;
- subnode.accessibilityLabel = label;
- [node addSubnode:subnode];
- XCTAssertEqualObjects([node.view.accessibilityElements.firstObject accessibilityLabel], label);
- // NOTE: The following tests will fail unless accessibility is enabled, e.g. by turning the
- // accessibility inspector on. See https://github.com/TextureGroup/Texture/pull/1069 for details.
- /*XCTAssertEqualObjects([[node.view accessibilityElementAtIndex:0] accessibilityLabel], label);
- XCTAssertEqual(node.view.accessibilityElementCount, 1);
- XCTAssertEqual([node.view indexOfAccessibilityElement:node.view.accessibilityElements.firstObject], 0);*/
-}
-
-- (void)testThatSubnodeAccessibilityLabelAggregationWorks
-{
- // Setup nodes
- ASDisplayNode *node = nil;
- ASDisplayNode *innerNode1 = nil;
- ASDisplayNode *innerNode2 = nil;
- node = [[ASDisplayNode alloc] init];
- innerNode1 = [[ASDisplayNode alloc] init];
- innerNode2 = [[ASDisplayNode alloc] init];
-
- // Initialize nodes with relevant accessibility data
- node.isAccessibilityContainer = YES;
- innerNode1.accessibilityLabel = @"hello";
- innerNode2.accessibilityLabel = @"world";
-
- // Attach the subnodes to the parent node, then ensure their accessibility labels have been'
- // aggregated to the parent's accessibility label
- [node addSubnode:innerNode1];
- [node addSubnode:innerNode2];
- XCTAssertEqualObjects([node.view.accessibilityElements.firstObject accessibilityLabel],
- @"hello, world", @"Subnode accessibility label aggregation broken %@",
- [node.view.accessibilityElements.firstObject accessibilityLabel]);
-}
-
-- (void)testThatContainerAccessibilityLabelOverrideStopsAggregation
-{
- // Setup nodes
- ASDisplayNode *node = nil;
- ASDisplayNode *innerNode = nil;
- node = [[ASDisplayNode alloc] init];
- innerNode = [[ASDisplayNode alloc] init];
-
- // Initialize nodes with relevant accessibility data
- node.isAccessibilityContainer = YES;
- node.accessibilityLabel = @"hello";
- innerNode.accessibilityLabel = @"world";
-
- // Attach the subnode to the parent node, then ensure the parent's accessibility label does not
- // get aggregated with the subnode's label
- [node addSubnode:innerNode];
- XCTAssertEqualObjects([node.view.accessibilityElements.firstObject accessibilityLabel], @"hello",
- @"Container accessibility label override broken %@",
- [node.view.accessibilityElements.firstObject accessibilityLabel]);
-}
-
-- (void)testAccessibilityLayerbackedNodesOperationInContainer {
- ASDisplayNode *contianer = [[ASDisplayNode alloc] init];
- contianer.frame = CGRectMake(50, 50, 200, 400);
- contianer.backgroundColor = [UIColor grayColor];
- contianer.isAccessibilityContainer = YES;
- // Do any additional setup after loading the view, typically from a nib.
- ASTextNode *text1 = [[ASTextNode alloc] init];
- text1.layerBacked = YES;
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"hello"];
- text1.frame = CGRectMake(50, 100, 200, 200);
- [contianer addSubnode:text1];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements = contianer.view.accessibilityElements;
- XCTAssertTrue(elements.count == 1);
- XCTAssertTrue([[elements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- ASTextNode *text2 = [[ASTextNode alloc] init];
- text2.layerBacked = YES;
- text2.attributedText = [[NSAttributedString alloc] initWithString:@"world"];
- text2.frame = CGRectMake(50, 300, 200, 200);
- [contianer addSubnode:text2];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements = contianer.view.accessibilityElements;
- XCTAssertTrue(updatedElements.count == 1);
- XCTAssertTrue([[updatedElements.firstObject accessibilityLabel] isEqualToString:@"hello, world"]);
- ASTextNode *text3 = [[ASTextNode alloc] init];
- text3.attributedText = [[NSAttributedString alloc] initWithString:@"!!!!"];
- text3.frame = CGRectMake(50, 400, 200, 100);
- text3.layerBacked = YES;
- [text2 addSubnode:text3];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements2 = contianer.view.accessibilityElements;
- XCTAssertTrue([[updatedElements2.firstObject accessibilityLabel] isEqualToString:@"hello, world, !!!!"]);
-}
-
-- (void)testAccessibilityNonLayerbackedNodesOperationInContainer
-{
- ASDisplayNode *contianer = [[ASDisplayNode alloc] init];
- contianer.frame = CGRectMake(50, 50, 200, 600);
- contianer.backgroundColor = [UIColor grayColor];
- contianer.isAccessibilityContainer = YES;
- // Do any additional setup after loading the view, typically from a nib.
- ASTextNode *text1 = [[ASTextNode alloc] init];
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"hello"];
- text1.frame = CGRectMake(50, 100, 200, 200);
- [contianer addSubnode:text1];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements = contianer.view.accessibilityElements;
- XCTAssertTrue(elements.count == 1);
- XCTAssertTrue([[elements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- ASTextNode *text2 = [[ASTextNode alloc] init];
- text2.attributedText = [[NSAttributedString alloc] initWithString:@"world"];
- text2.frame = CGRectMake(50, 300, 200, 200);
- [contianer addSubnode:text2];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements = contianer.view.accessibilityElements;
- XCTAssertTrue(updatedElements.count == 1);
- XCTAssertTrue([[updatedElements.firstObject accessibilityLabel] isEqualToString:@"hello, world"]);
- ASTextNode *text3 = [[ASTextNode alloc] init];
- text3.attributedText = [[NSAttributedString alloc] initWithString:@"!!!!"];
- text3.frame = CGRectMake(50, 400, 200, 100);
- [text2 addSubnode:text3];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements2 = contianer.view.accessibilityElements;
- XCTAssertTrue([[updatedElements2.firstObject accessibilityLabel] isEqualToString:@"hello, world, !!!!"]);
-}
-
-- (void)testAccessibilityNonLayerbackedNodesOperationInNonContainer
-{
- ASDisplayNode *contianer = [[ASDisplayNode alloc] init];
- contianer.frame = CGRectMake(50, 50, 200, 600);
- contianer.backgroundColor = [UIColor grayColor];
- // Do any additional setup after loading the view, typically from a nib.
- ASTextNode *text1 = [[ASTextNode alloc] init];
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"hello"];
- text1.frame = CGRectMake(50, 100, 200, 200);
- [contianer addSubnode:text1];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements = contianer.view.accessibilityElements;
- XCTAssertTrue(elements.count == 1);
- XCTAssertTrue([[elements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- ASTextNode *text2 = [[ASTextNode alloc] init];
- text2.attributedText = [[NSAttributedString alloc] initWithString:@"world"];
- text2.frame = CGRectMake(50, 300, 200, 200);
- [contianer addSubnode:text2];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements = contianer.view.accessibilityElements;
- XCTAssertTrue(updatedElements.count == 2);
- XCTAssertTrue([[updatedElements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- XCTAssertTrue([[updatedElements.lastObject accessibilityLabel] isEqualToString:@"world"]);
- ASTextNode *text3 = [[ASTextNode alloc] init];
- text3.attributedText = [[NSAttributedString alloc] initWithString:@"!!!!"];
- text3.frame = CGRectMake(50, 400, 200, 100);
- [text2 addSubnode:text3];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements2 = contianer.view.accessibilityElements;
- //text3 won't be read out cause it's overshadowed by text2
- XCTAssertTrue(updatedElements2.count == 2);
- XCTAssertTrue([[updatedElements2.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- XCTAssertTrue([[updatedElements2.lastObject accessibilityLabel] isEqualToString:@"world"]);
-}
-- (void)testAccessibilityLayerbackedNodesOperationInNonContainer
-{
- ASDisplayNode *contianer = [[ASDisplayNode alloc] init];
- contianer.frame = CGRectMake(50, 50, 200, 600);
- contianer.backgroundColor = [UIColor grayColor];
- // Do any additional setup after loading the view, typically from a nib.
- ASTextNode *text1 = [[ASTextNode alloc] init];
- text1.layerBacked = YES;
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"hello"];
- text1.frame = CGRectMake(50, 0, 100, 100);
- [contianer addSubnode:text1];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements = contianer.view.accessibilityElements;
- XCTAssertTrue(elements.count == 1);
- XCTAssertTrue([[elements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- ASTextNode *text2 = [[ASTextNode alloc] init];
- text2.layerBacked = YES;
- text2.attributedText = [[NSAttributedString alloc] initWithString:@"world"];
- text2.frame = CGRectMake(50, 100, 100, 100);
- [contianer addSubnode:text2];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements = contianer.view.accessibilityElements;
- XCTAssertTrue(updatedElements.count == 2);
- XCTAssertTrue([[updatedElements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- XCTAssertTrue([[updatedElements.lastObject accessibilityLabel] isEqualToString:@"world"]);
- ASTextNode *text3 = [[ASTextNode alloc] init];
- text3.layerBacked = YES;
- text3.attributedText = [[NSAttributedString alloc] initWithString:@"!!!!"];
- text3.frame = CGRectMake(50, 200, 100, 100);
- [text2 addSubnode:text3];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *updatedElements2 = contianer.view.accessibilityElements;
- //text3 won't be read out cause it's overshadowed by text2
- XCTAssertTrue(updatedElements2.count == 2);
- XCTAssertTrue([[updatedElements2.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- XCTAssertTrue([[updatedElements2.lastObject accessibilityLabel] isEqualToString:@"world"]);
-}
-
-- (void)testAccessibilityUpdatesWithElementsChanges
-{
- ASDisplayNode *contianer = [[ASDisplayNode alloc] init];
- contianer.frame = CGRectMake(50, 50, 200, 600);
- contianer.backgroundColor = [UIColor grayColor];
- contianer.isAccessibilityContainer = YES;
- // Do any additional setup after loading the view, typically from a nib.
- ASTextNode *text1 = [[ASTextNode alloc] init];
- text1.layerBacked = YES;
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"hello"];
- text1.frame = CGRectMake(50, 0, 100, 100);
- [contianer addSubnode:text1];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements = contianer.view.accessibilityElements;
- XCTAssertTrue(elements.count == 1);
- XCTAssertTrue([[elements.firstObject accessibilityLabel] isEqualToString:@"hello"]);
- text1.attributedText = [[NSAttributedString alloc] initWithString:@"greeting"];
- [contianer layoutIfNeeded];
- [contianer.layer displayIfNeeded];
- NSArray *elements2 = contianer.view.accessibilityElements;
- XCTAssertTrue(elements2.count == 1);
- XCTAssertTrue([[elements2.firstObject accessibilityLabel] isEqualToString:@"greeting"]);
-}
-
-#pragma mark -
-#pragma mark UIAccessibilityAction Forwarding
-
-- (void)testActionForwarding {
- ASDisplayNode *node = [ASDisplayNode new];
- UIView *view = node.view;
-
- id mockNode = OCMPartialMock(node);
-
- OCMExpect([mockNode accessibilityActivate]);
- [view accessibilityActivate];
-
- OCMExpect([mockNode accessibilityIncrement]);
- [view accessibilityIncrement];
-
- OCMExpect([mockNode accessibilityDecrement]);
- [view accessibilityDecrement];
-
- OCMExpect([mockNode accessibilityScroll:UIAccessibilityScrollDirectionDown]);
- [view accessibilityScroll:UIAccessibilityScrollDirectionDown];
-
- OCMExpect([mockNode accessibilityPerformEscape]);
- [view accessibilityPerformEscape];
-
- OCMExpect([mockNode accessibilityPerformMagicTap]);
- [view accessibilityPerformMagicTap];
-
- OCMVerifyAll(mockNode);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASEditableTextNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASEditableTextNodeTests.mm
deleted file mode 100644
index a359629014..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASEditableTextNodeTests.mm
+++ /dev/null
@@ -1,171 +0,0 @@
-//
-// ASEditableTextNodeTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-
-static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta)
-{
- return fabs(size1.width - size2.width) < delta && fabs(size1.height - size2.height) < delta;
-}
-
-@interface ASEditableTextNodeTests : XCTestCase
-@property (nonatomic) ASEditableTextNode *editableTextNode;
-@property (nonatomic, copy) NSAttributedString *attributedText;
-@end
-
-@implementation ASEditableTextNodeTests
-
-- (void)setUp
-{
- [super setUp];
-
- _editableTextNode = [[ASEditableTextNode alloc] init];
-
- NSMutableAttributedString *mas = [[NSMutableAttributedString alloc] initWithString:@"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."];
- NSMutableParagraphStyle *para = [NSMutableParagraphStyle new];
- para.alignment = NSTextAlignmentCenter;
- para.lineSpacing = 1.0;
- [mas addAttribute:NSParagraphStyleAttributeName value:para
- range:NSMakeRange(0, mas.length - 1)];
-
- // Vary the linespacing on the last line
- NSMutableParagraphStyle *lastLinePara = [NSMutableParagraphStyle new];
- lastLinePara.alignment = para.alignment;
- lastLinePara.lineSpacing = 5.0;
- [mas addAttribute:NSParagraphStyleAttributeName value:lastLinePara
- range:NSMakeRange(mas.length - 1, 1)];
-
- _attributedText = mas;
- _editableTextNode.attributedText = _attributedText;
-}
-
-#pragma mark - ASEditableTextNode
-
-- (void)testAllocASEditableTextNode
-{
- ASEditableTextNode *node = [[ASEditableTextNode alloc] init];
- XCTAssertTrue([[node class] isSubclassOfClass:[ASEditableTextNode class]], @"ASEditableTextNode alloc should return an instance of ASEditableTextNode, instead returned %@", [node class]);
-}
-
-#pragma mark - ASEditableTextNode Tests
-
-- (void)testUITextInputTraitDefaults
-{
- ASEditableTextNode *editableTextNode = [[ASEditableTextNode alloc] init];
-
- XCTAssertTrue(editableTextNode.autocapitalizationType == UITextAutocapitalizationTypeSentences, @"_ASTextInputTraitsPendingState's autocapitalizationType default should be UITextAutocapitalizationTypeSentences.");
- XCTAssertTrue(editableTextNode.autocorrectionType == UITextAutocorrectionTypeDefault, @"_ASTextInputTraitsPendingState's autocorrectionType default should be UITextAutocorrectionTypeDefault.");
- XCTAssertTrue(editableTextNode.spellCheckingType == UITextSpellCheckingTypeDefault, @"_ASTextInputTraitsPendingState's spellCheckingType default should be UITextSpellCheckingTypeDefault.");
- XCTAssertTrue(editableTextNode.keyboardType == UIKeyboardTypeDefault, @"_ASTextInputTraitsPendingState's keyboardType default should be UIKeyboardTypeDefault.");
- XCTAssertTrue(editableTextNode.keyboardAppearance == UIKeyboardAppearanceDefault, @"_ASTextInputTraitsPendingState's keyboardAppearance default should be UIKeyboardAppearanceDefault.");
- XCTAssertTrue(editableTextNode.returnKeyType == UIReturnKeyDefault, @"_ASTextInputTraitsPendingState's returnKeyType default should be UIReturnKeyDefault.");
- XCTAssertTrue(editableTextNode.enablesReturnKeyAutomatically == NO, @"_ASTextInputTraitsPendingState's enablesReturnKeyAutomatically default should be NO.");
- XCTAssertTrue(editableTextNode.isSecureTextEntry == NO, @"_ASTextInputTraitsPendingState's isSecureTextEntry default should be NO.");
-
- XCTAssertTrue(editableTextNode.textView.autocapitalizationType == UITextAutocapitalizationTypeSentences, @"textView's autocapitalizationType default should be UITextAutocapitalizationTypeSentences.");
- XCTAssertTrue(editableTextNode.textView.autocorrectionType == UITextAutocorrectionTypeDefault, @"textView's autocorrectionType default should be UITextAutocorrectionTypeDefault.");
- XCTAssertTrue(editableTextNode.textView.spellCheckingType == UITextSpellCheckingTypeDefault, @"textView's spellCheckingType default should be UITextSpellCheckingTypeDefault.");
- XCTAssertTrue(editableTextNode.textView.keyboardType == UIKeyboardTypeDefault, @"textView's keyboardType default should be UIKeyboardTypeDefault.");
- XCTAssertTrue(editableTextNode.textView.keyboardAppearance == UIKeyboardAppearanceDefault, @"textView's keyboardAppearance default should be UIKeyboardAppearanceDefault.");
- XCTAssertTrue(editableTextNode.textView.returnKeyType == UIReturnKeyDefault, @"textView's returnKeyType default should be UIReturnKeyDefault.");
- XCTAssertTrue(editableTextNode.textView.enablesReturnKeyAutomatically == NO, @"textView's enablesReturnKeyAutomatically default should be NO.");
- XCTAssertTrue(editableTextNode.textView.isSecureTextEntry == NO, @"textView's isSecureTextEntry default should be NO.");
-}
-
-- (void)testUITextInputTraitsSetTraitsBeforeViewLoaded
-{
- // UITextView ignores any values set on the first 3 properties below if secureTextEntry is enabled.
- // Because of this UIKit behavior, we'll test secure entry seperately
- ASEditableTextNode *editableTextNode = [[ASEditableTextNode alloc] init];
-
- editableTextNode.autocapitalizationType = UITextAutocapitalizationTypeWords;
- editableTextNode.autocorrectionType = UITextAutocorrectionTypeYes;
- editableTextNode.spellCheckingType = UITextSpellCheckingTypeYes;
- editableTextNode.keyboardType = UIKeyboardTypeTwitter;
- editableTextNode.keyboardAppearance = UIKeyboardAppearanceDark;
- editableTextNode.returnKeyType = UIReturnKeyGo;
- editableTextNode.enablesReturnKeyAutomatically = YES;
-
- XCTAssertTrue(editableTextNode.textView.autocapitalizationType == UITextAutocapitalizationTypeWords, @"textView's autocapitalizationType should be UITextAutocapitalizationTypeAllCharacters.");
- XCTAssertTrue(editableTextNode.textView.autocorrectionType == UITextAutocorrectionTypeYes, @"textView's autocorrectionType should be UITextAutocorrectionTypeYes.");
- XCTAssertTrue(editableTextNode.textView.spellCheckingType == UITextSpellCheckingTypeYes, @"textView's spellCheckingType should be UITextSpellCheckingTypeYes.");
- XCTAssertTrue(editableTextNode.textView.keyboardType == UIKeyboardTypeTwitter, @"textView's keyboardType should be UIKeyboardTypeTwitter.");
- XCTAssertTrue(editableTextNode.textView.keyboardAppearance == UIKeyboardAppearanceDark, @"textView's keyboardAppearance should be UIKeyboardAppearanceDark.");
- XCTAssertTrue(editableTextNode.textView.returnKeyType == UIReturnKeyGo, @"textView's returnKeyType should be UIReturnKeyGo.");
- XCTAssertTrue(editableTextNode.textView.enablesReturnKeyAutomatically == YES, @"textView's enablesReturnKeyAutomatically should be YES.");
-
- ASEditableTextNode *secureEditableTextNode = [[ASEditableTextNode alloc] init];
- secureEditableTextNode.secureTextEntry = YES;
-
- XCTAssertTrue(secureEditableTextNode.textView.secureTextEntry == YES, @"textView's isSecureTextEntry should be YES.");
-}
-
-- (void)testUITextInputTraitsChangeTraitAfterViewLoaded
-{
- // UITextView ignores any values set on the first 3 properties below if secureTextEntry is enabled.
- // Because of this UIKit behavior, we'll test secure entry seperately
- ASEditableTextNode *editableTextNode = [[ASEditableTextNode alloc] init];
-
- editableTextNode.textView.autocapitalizationType = UITextAutocapitalizationTypeWords;
- editableTextNode.textView.autocorrectionType = UITextAutocorrectionTypeYes;
- editableTextNode.textView.spellCheckingType = UITextSpellCheckingTypeYes;
- editableTextNode.textView.keyboardType = UIKeyboardTypeTwitter;
- editableTextNode.textView.keyboardAppearance = UIKeyboardAppearanceDark;
- editableTextNode.textView.returnKeyType = UIReturnKeyGo;
- editableTextNode.textView.enablesReturnKeyAutomatically = YES;
-
- XCTAssertTrue(editableTextNode.textView.autocapitalizationType == UITextAutocapitalizationTypeWords, @"textView's autocapitalizationType should be UITextAutocapitalizationTypeAllCharacters.");
- XCTAssertTrue(editableTextNode.textView.autocorrectionType == UITextAutocorrectionTypeYes, @"textView's autocorrectionType should be UITextAutocorrectionTypeYes.");
- XCTAssertTrue(editableTextNode.textView.spellCheckingType == UITextSpellCheckingTypeYes, @"textView's spellCheckingType should be UITextSpellCheckingTypeYes.");
- XCTAssertTrue(editableTextNode.textView.keyboardType == UIKeyboardTypeTwitter, @"textView's keyboardType should be UIKeyboardTypeTwitter.");
- XCTAssertTrue(editableTextNode.textView.keyboardAppearance == UIKeyboardAppearanceDark, @"textView's keyboardAppearance should be UIKeyboardAppearanceDark.");
- XCTAssertTrue(editableTextNode.textView.returnKeyType == UIReturnKeyGo, @"textView's returnKeyType should be UIReturnKeyGo.");
- XCTAssertTrue(editableTextNode.textView.enablesReturnKeyAutomatically == YES, @"textView's enablesReturnKeyAutomatically should be YES.");
-
- ASEditableTextNode *secureEditableTextNode = [[ASEditableTextNode alloc] init];
- secureEditableTextNode.textView.secureTextEntry = YES;
-
- XCTAssertTrue(secureEditableTextNode.textView.secureTextEntry == YES, @"textView's isSecureTextEntry should be YES.");
-}
-
-- (void)testCalculatedSizeIsGreaterThanOrEqualToConstrainedSize
-{
- for (NSInteger i = 10; i < 500; i += 50) {
- CGSize constrainedSize = CGSizeMake(i, i);
- CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size;
- XCTAssertTrue(calculatedSize.width <= constrainedSize.width, @"Calculated width (%f) should be less than or equal to constrained width (%f)", calculatedSize.width, constrainedSize.width);
- XCTAssertTrue(calculatedSize.height <= constrainedSize.height, @"Calculated height (%f) should be less than or equal to constrained height (%f)", calculatedSize.height, constrainedSize.height);
- }
-}
-
-- (void)testRecalculationOfSizeIsSameAsOriginallyCalculatedSize
-{
- for (NSInteger i = 10; i < 500; i += 50) {
- CGSize constrainedSize = CGSizeMake(i, i);
- CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size;
- CGSize recalculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size;
-
- XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 4.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize));
- }
-}
-
-- (void)testRecalculationOfSizeIsSameAsOriginallyCalculatedFloatingPointSize
-{
- for (CGFloat i = 10; i < 500; i *= 1.3) {
- CGSize constrainedSize = CGSizeMake(i, i);
- CGSize calculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size;
- CGSize recalculatedSize = [_editableTextNode layoutThatFits:ASSizeRangeMake(CGSizeZero, constrainedSize)].size;
-
- XCTAssertTrue(CGSizeEqualToSizeWithIn(calculatedSize, recalculatedSize, 11.0), @"Recalculated size %@ should be same as original size %@", NSStringFromCGSize(recalculatedSize), NSStringFromCGSize(calculatedSize));
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASImageNodeSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASImageNodeSnapshotTests.mm
deleted file mode 100644
index 55cb5f866e..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASImageNodeSnapshotTests.mm
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// ASImageNodeSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASSnapshotTestCase.h"
-
-#import
-
-@interface ASImageNodeSnapshotTests : ASSnapshotTestCase
-@end
-
-@implementation ASImageNodeSnapshotTests
-
-- (void)setUp
-{
- [super setUp];
-
- self.recordMode = NO;
-}
-
-- (UIImage *)testImage
-{
- NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo-square"
- ofType:@"png"
- inDirectory:@"TestResources"];
- return [UIImage imageWithContentsOfFile:path];
-}
-
-- (void)testRenderLogoSquare
-{
- // trivial test case to ensure ASSnapshotTestCase works
- ASImageNode *imageNode = [[ASImageNode alloc] init];
- imageNode.image = [self testImage];
- ASDisplayNodeSizeToFitSize(imageNode, CGSizeMake(100, 100));
-
- ASSnapshotVerifyNode(imageNode, nil);
-}
-
-- (void)testForcedScaling
-{
- CGSize forcedImageSize = CGSizeMake(100, 100);
-
- ASImageNode *imageNode = [[ASImageNode alloc] init];
- imageNode.forcedSize = forcedImageSize;
- imageNode.image = [self testImage];
-
- // Snapshot testing requires that node is formally laid out.
- imageNode.style.width = ASDimensionMake(forcedImageSize.width);
- imageNode.style.height = ASDimensionMake(forcedImageSize.height);
- ASDisplayNodeSizeToFitSize(imageNode, forcedImageSize);
- ASSnapshotVerifyNode(imageNode, @"first");
-
- imageNode.style.width = ASDimensionMake(200);
- imageNode.style.height = ASDimensionMake(200);
- ASDisplayNodeSizeToFitSize(imageNode, CGSizeMake(200, 200));
- ASSnapshotVerifyNode(imageNode, @"second");
-
- XCTAssert(CGImageGetWidth((CGImageRef)imageNode.contents) == forcedImageSize.width * imageNode.contentsScale &&
- CGImageGetHeight((CGImageRef)imageNode.contents) == forcedImageSize.height * imageNode.contentsScale,
- @"Contents should be 100 x 100 by contents scale.");
-}
-
-- (void)testTintColorBlock
-{
- UIImage *test = [self testImage];
- UIImage *tinted = ASImageNodeTintColorModificationBlock([UIColor redColor])(test);
- ASImageNode *node = [[ASImageNode alloc] init];
- node.image = tinted;
- ASDisplayNodeSizeToFitSize(node, test.size);
-
- ASSnapshotVerifyNode(node, nil);
-}
-
-- (void)testRoundedCornerBlock
-{
- UIGraphicsBeginImageContext(CGSizeMake(100, 100));
- [[UIColor blueColor] setFill];
- UIRectFill(CGRectMake(0, 0, 100, 100));
- UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- UIImage *rounded = ASImageNodeRoundBorderModificationBlock(2, [UIColor redColor])(result);
- ASImageNode *node = [[ASImageNode alloc] init];
- node.image = rounded;
- ASDisplayNodeSizeToFitSize(node, rounded.size);
-
- ASSnapshotVerifyNode(node, nil);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASInsetLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASInsetLayoutSpecSnapshotTests.mm
deleted file mode 100644
index d6047d35f3..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASInsetLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,117 +0,0 @@
-//
-// ASInsetLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-
-typedef NS_OPTIONS(NSUInteger, ASInsetLayoutSpecTestEdge) {
- ASInsetLayoutSpecTestEdgeTop = 1 << 0,
- ASInsetLayoutSpecTestEdgeLeft = 1 << 1,
- ASInsetLayoutSpecTestEdgeBottom = 1 << 2,
- ASInsetLayoutSpecTestEdgeRight = 1 << 3,
-};
-
-static CGFloat insetForEdge(NSUInteger combination, ASInsetLayoutSpecTestEdge edge, CGFloat insetValue)
-{
- return combination & edge ? INFINITY : insetValue;
-}
-
-static UIEdgeInsets insetsForCombination(NSUInteger combination, CGFloat insetValue)
-{
- return {
- .top = insetForEdge(combination, ASInsetLayoutSpecTestEdgeTop, insetValue),
- .left = insetForEdge(combination, ASInsetLayoutSpecTestEdgeLeft, insetValue),
- .bottom = insetForEdge(combination, ASInsetLayoutSpecTestEdgeBottom, insetValue),
- .right = insetForEdge(combination, ASInsetLayoutSpecTestEdgeRight, insetValue),
- };
-}
-
-static NSString *nameForInsets(UIEdgeInsets insets)
-{
- return [NSString stringWithFormat:@"%.f-%.f-%.f-%.f", insets.top, insets.left, insets.bottom, insets.right];
-}
-
-@interface ASInsetLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-@end
-
-@implementation ASInsetLayoutSpecSnapshotTests
-
-- (void)testInsetsWithVariableSize
-{
- for (NSUInteger combination = 0; combination < 16; combination++) {
- UIEdgeInsets insets = insetsForCombination(combination, 10);
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10});
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASInsetLayoutSpec
- insetLayoutSpecWithInsets:insets
- child:foregroundNode]
- background:backgroundNode];
-
- static ASSizeRange kVariableSize = {{0, 0}, {300, 300}};
- [self testLayoutSpec:layoutSpec
- sizeRange:kVariableSize
- subnodes:@[backgroundNode, foregroundNode]
- identifier:nameForInsets(insets)];
- }
-}
-
-- (void)testInsetsWithFixedSize
-{
- for (NSUInteger combination = 0; combination < 16; combination++) {
- UIEdgeInsets insets = insetsForCombination(combination, 10);
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10});
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASInsetLayoutSpec
- insetLayoutSpecWithInsets:insets
- child:foregroundNode]
- background:backgroundNode];
-
- static ASSizeRange kFixedSize = {{300, 300}, {300, 300}};
- [self testLayoutSpec:layoutSpec
- sizeRange:kFixedSize
- subnodes:@[backgroundNode, foregroundNode]
- identifier:nameForInsets(insets)];
- }
-}
-
-/** Regression test, there was a bug mixing insets with infinite and zero sizes */
-- (void)testInsetsWithInfinityAndZeroInsetValue
-{
- for (NSUInteger combination = 0; combination < 16; combination++) {
- UIEdgeInsets insets = insetsForCombination(combination, 0);
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor grayColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], {10, 10});
-
- ASLayoutSpec *layoutSpec =
- [ASBackgroundLayoutSpec
- backgroundLayoutSpecWithChild:
- [ASInsetLayoutSpec
- insetLayoutSpecWithInsets:insets
- child:foregroundNode]
- background:backgroundNode];
-
- static ASSizeRange kFixedSize = {{300, 300}, {300, 300}};
- [self testLayoutSpec:layoutSpec
- sizeRange:kFixedSize
- subnodes:@[backgroundNode, foregroundNode]
- identifier:nameForInsets(insets)];
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASIntegerMapTests.mm b/submodules/AsyncDisplayKit/Tests/ASIntegerMapTests.mm
deleted file mode 100644
index d23e5bf49f..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASIntegerMapTests.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-//
-// ASIntegerMapTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASTestCase.h"
-#import "ASIntegerMap.h"
-
-@interface ASIntegerMapTests : ASTestCase
-
-@end
-
-@implementation ASIntegerMapTests
-
-- (void)testIsEqual
-{
- ASIntegerMap *map = [[ASIntegerMap alloc] init];
- [map setInteger:1 forKey:0];
- ASIntegerMap *alsoMap = [[ASIntegerMap alloc] init];
- [alsoMap setInteger:1 forKey:0];
- ASIntegerMap *notMap = [[ASIntegerMap alloc] init];
- [notMap setInteger:2 forKey:0];
- XCTAssertEqualObjects(map, alsoMap);
- XCTAssertNotEqualObjects(map, notMap);
-}
-
-#pragma mark - Changeset mapping
-
-/// 1 item, no changes -> identity map
-- (void)testEmptyChange
-{
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:1 deleted:nil inserted:nil];
- XCTAssertEqual(map, ASIntegerMap.identityMap);
-}
-
-/// 0 items -> empty map
-- (void)testChangeOnNoData
-{
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:0 deleted:nil inserted:nil];
- XCTAssertEqual(map, ASIntegerMap.emptyMap);
-}
-
-/// 2 items, delete 0
-- (void)testBasicChange1
-{
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:2 deleted:[NSIndexSet indexSetWithIndex:0] inserted:nil];
- XCTAssertEqual([map integerForKey:0], NSNotFound);
- XCTAssertEqual([map integerForKey:1], 0);
- XCTAssertEqual([map integerForKey:2], NSNotFound);
-}
-
-/// 2 items, insert 0
-- (void)testBasicChange2
-{
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:2 deleted:nil inserted:[NSIndexSet indexSetWithIndex:0]];
- XCTAssertEqual([map integerForKey:0], 1);
- XCTAssertEqual([map integerForKey:1], 2);
- XCTAssertEqual([map integerForKey:2], NSNotFound);
-}
-
-/// 2 items, insert 0, delete 0
-- (void)testChange1
-{
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:2 deleted:[NSIndexSet indexSetWithIndex:0] inserted:[NSIndexSet indexSetWithIndex:0]];
- XCTAssertEqual([map integerForKey:0], NSNotFound);
- XCTAssertEqual([map integerForKey:1], 1);
- XCTAssertEqual([map integerForKey:2], NSNotFound);
-}
-
-/// 4 items, insert {0-1, 3}
-- (void)testChange2
-{
- NSMutableIndexSet *inserts = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
- [inserts addIndex:3];
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:4 deleted:nil inserted:inserts];
- XCTAssertEqual([map integerForKey:0], 2);
- XCTAssertEqual([map integerForKey:1], 4);
- XCTAssertEqual([map integerForKey:2], 5);
- XCTAssertEqual([map integerForKey:3], 6);
-}
-
-/// 4 items, delete {0-1, 3}
-- (void)testChange3
-{
- NSMutableIndexSet *deletes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
- [deletes addIndex:3];
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:4 deleted:deletes inserted:nil];
- XCTAssertEqual([map integerForKey:0], NSNotFound);
- XCTAssertEqual([map integerForKey:1], NSNotFound);
- XCTAssertEqual([map integerForKey:2], 0);
- XCTAssertEqual([map integerForKey:3], NSNotFound);
-}
-
-/// 5 items, delete {0-1, 3} insert {1-2, 4}
-- (void)testChange4
-{
- NSMutableIndexSet *deletes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
- [deletes addIndex:3];
- NSMutableIndexSet *inserts = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)];
- [inserts addIndex:4];
- ASIntegerMap *map = [ASIntegerMap mapForUpdateWithOldCount:5 deleted:deletes inserted:inserts];
- XCTAssertEqual([map integerForKey:0], NSNotFound);
- XCTAssertEqual([map integerForKey:1], NSNotFound);
- XCTAssertEqual([map integerForKey:2], 0);
- XCTAssertEqual([map integerForKey:3], NSNotFound);
- XCTAssertEqual([map integerForKey:4], 3);
- XCTAssertEqual([map integerForKey:5], NSNotFound);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutElementStyleTests.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutElementStyleTests.mm
deleted file mode 100644
index f6f95066e8..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutElementStyleTests.mm
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// ASLayoutElementStyleTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import "ASXCTExtensions.h"
-#import
-
-#pragma mark - ASLayoutElementStyleTestsDelegate
-
-@interface ASLayoutElementStyleTestsDelegate : NSObject
-@property (copy, nonatomic) NSString *propertyNameChanged;
-@end
-
-@implementation ASLayoutElementStyleTestsDelegate
-
-- (void)style:(id)style propertyDidChange:(NSString *)propertyName
-{
- self.propertyNameChanged = propertyName;
-}
-
-@end
-
-#pragma mark - ASLayoutElementStyleTests
-
-@interface ASLayoutElementStyleTests : XCTestCase
-
-@end
-
-@implementation ASLayoutElementStyleTests
-
-- (void)testSettingSize
-{
- ASLayoutElementStyle *style = [ASLayoutElementStyle new];
-
- style.width = ASDimensionMake(100);
- style.height = ASDimensionMake(100);
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionMake(100)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.height, ASDimensionMake(100)));
-
- style.minWidth = ASDimensionMake(100);
- style.minHeight = ASDimensionMake(100);
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionMake(100)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.height, ASDimensionMake(100)));
-
- style.maxWidth = ASDimensionMake(100);
- style.maxHeight = ASDimensionMake(100);
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionMake(100)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.height, ASDimensionMake(100)));
-}
-
-- (void)testSettingSizeViaCGSize
-{
- ASLayoutElementStyle *style = [ASLayoutElementStyle new];
-
- ASXCTAssertEqualSizes(style.preferredSize, CGSizeZero);
-
- CGSize size = CGSizeMake(100, 100);
-
- style.preferredSize = size;
- ASXCTAssertEqualSizes(style.preferredSize, size);
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionMakeWithPoints(size.width)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.height, ASDimensionMakeWithPoints(size.height)));
-
- style.minSize = size;
- XCTAssertTrue(ASDimensionEqualToDimension(style.minWidth, ASDimensionMakeWithPoints(size.width)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.minHeight, ASDimensionMakeWithPoints(size.height)));
-
- style.maxSize = size;
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxWidth, ASDimensionMakeWithPoints(size.width)));
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxHeight, ASDimensionMakeWithPoints(size.height)));
-}
-
-- (void)testReadingInvalidSizeForPreferredSize
-{
- ASLayoutElementStyle *style = [ASLayoutElementStyle new];
-
- XCTAssertNoThrow(style.preferredSize);
-
- style.width = ASDimensionMake(ASDimensionUnitFraction, 0.5);
- XCTAssertThrows(style.preferredSize);
-
- style.preferredSize = CGSizeMake(100, 100);
- XCTAssertNoThrow(style.preferredSize);
-}
-
-- (void)testSettingSizeViaLayoutSize
-{
- ASLayoutElementStyle *style = [ASLayoutElementStyle new];
-
- ASLayoutSize layoutSize = ASLayoutSizeMake(ASDimensionMake(100), ASDimensionMake(100));
-
- style.preferredLayoutSize = layoutSize;
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.height, layoutSize.height));
- XCTAssertTrue(ASDimensionEqualToDimension(style.preferredLayoutSize.width, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.preferredLayoutSize.height, layoutSize.height));
-
- style.minLayoutSize = layoutSize;
- XCTAssertTrue(ASDimensionEqualToDimension(style.minWidth, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.minHeight, layoutSize.height));
- XCTAssertTrue(ASDimensionEqualToDimension(style.minLayoutSize.width, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.minLayoutSize.height, layoutSize.height));
-
- style.maxLayoutSize = layoutSize;
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxWidth, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxHeight, layoutSize.height));
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxLayoutSize.width, layoutSize.width));
- XCTAssertTrue(ASDimensionEqualToDimension(style.maxLayoutSize.height, layoutSize.height));
-}
-
-- (void)testSettingPropertiesWillCallDelegate
-{
- ASLayoutElementStyleTestsDelegate *delegate = [ASLayoutElementStyleTestsDelegate new];
- ASLayoutElementStyle *style = [[ASLayoutElementStyle alloc] initWithDelegate:delegate];
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionAuto));
- style.width = ASDimensionMake(100);
- XCTAssertTrue(ASDimensionEqualToDimension(style.width, ASDimensionMake(100)));
- XCTAssertTrue([delegate.propertyNameChanged isEqualToString:ASLayoutElementStyleWidthProperty]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutEngineTests.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutEngineTests.mm
deleted file mode 100644
index 3222f78b5f..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutEngineTests.mm
+++ /dev/null
@@ -1,591 +0,0 @@
-//
-// ASLayoutEngineTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASTestCase.h"
-#import "ASLayoutTestNode.h"
-#import "ASXCTExtensions.h"
-#import "ASTLayoutFixture.h"
-
-@interface ASLayoutEngineTests : ASTestCase
-
-@end
-
-@implementation ASLayoutEngineTests {
- ASLayoutTestNode *nodeA;
- ASLayoutTestNode *nodeB;
- ASLayoutTestNode *nodeC;
- ASLayoutTestNode *nodeD;
- ASLayoutTestNode *nodeE;
- ASTLayoutFixture *fixture1;
- ASTLayoutFixture *fixture2;
- ASTLayoutFixture *fixture3;
- ASTLayoutFixture *fixture4;
- ASTLayoutFixture *fixture5;
-
- // fixtures 1, 3 and 5 share the same exact node A layout spec block.
- // we don't want the infra to call -setNeedsLayout when we switch fixtures
- // so we need to use the same exact block.
- ASLayoutSpecBlock fixture1and3and5NodeALayoutSpecBlock;
-
- UIWindow *window;
- UIViewController *vc;
- NSArray *allNodes;
- NSTimeInterval verifyDelay;
- // See -stubCalculatedLayoutDidChange.
- BOOL stubbedCalculatedLayoutDidChange;
-}
-
-- (void)setUp
-{
- [super setUp];
- verifyDelay = 3;
- window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 10, 1)];
- vc = [[UIViewController alloc] init];
- nodeA = [ASLayoutTestNode new];
- nodeA.backgroundColor = [UIColor redColor];
-
- // NOTE: nodeB has flexShrink, the others don't
- nodeB = [ASLayoutTestNode new];
- nodeB.style.flexShrink = 1;
- nodeB.backgroundColor = [UIColor orangeColor];
-
- nodeC = [ASLayoutTestNode new];
- nodeC.backgroundColor = [UIColor yellowColor];
- nodeD = [ASLayoutTestNode new];
- nodeD.backgroundColor = [UIColor greenColor];
- nodeE = [ASLayoutTestNode new];
- nodeE.backgroundColor = [UIColor blueColor];
- allNodes = @[ nodeA, nodeB, nodeC, nodeD, nodeE ];
- ASSetDebugNames(nodeA, nodeB, nodeC, nodeD, nodeE);
- ASLayoutSpecBlock b = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeD ]];
- };
- fixture1and3and5NodeALayoutSpecBlock = b;
- fixture1 = [self createFixture1];
- fixture2 = [self createFixture2];
- fixture3 = [self createFixture3];
- fixture4 = [self createFixture4];
- fixture5 = [self createFixture5];
-
- nodeA.frame = vc.view.bounds;
- nodeA.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [vc.view addSubnode:nodeA];
-
- window.rootViewController = vc;
- [window makeKeyAndVisible];
-}
-
-- (void)tearDown
-{
- nodeA.layoutSpecBlock = nil;
- for (ASLayoutTestNode *node in allNodes) {
- OCMVerifyAllWithDelay(node.mock, verifyDelay);
- }
- [super tearDown];
-}
-
-- (void)testFirstLayoutPassWhenInWindow
-{
- [self runFirstLayoutPassWithFixture:fixture1];
-}
-
-- (void)testSetNeedsLayoutAndNormalLayoutPass
-{
- [self runFirstLayoutPassWithFixture:fixture1];
-
- [fixture2 apply];
-
- // skip nodeB because its layout doesn't change.
- for (ASLayoutTestNode *node in @[ nodeA, nodeC, nodeE ]) {
- [fixture2 withSizeRangesForNode:node block:^(ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange]).onMainThread();
- }];
- OCMExpect([node.mock calculatedLayoutDidChange]).onMainThread();
- }
-
- [window layoutIfNeeded];
- [self verifyFixture:fixture2];
-}
-
-/**
- * Transition from fixture1 to Fixture2 on node A.
- *
- * Expect A and D to calculate once off main, and
- * to receive calculatedLayoutDidChange on main,
- * then to get the measurement completion call on main,
- * then to get animateLayoutTransition: and didCompleteLayoutTransition: on main.
- */
-- (void)testLayoutTransitionWithAsyncMeasurement
-{
- [self stubCalculatedLayoutDidChange];
- [self runFirstLayoutPassWithFixture:fixture1];
-
- [fixture2 apply];
-
- // Expect A, C, E to calculate new layouts off-main
- // dispatch_once onto main to run our injectedMainThread work while the transition calculates.
- __block dispatch_block_t injectedMainThreadWork = nil;
- for (ASLayoutTestNode *node in @[ nodeA, nodeC, nodeE ]) {
- [fixture2 withSizeRangesForNode:node block:^(ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange])
- .offMainThread()
- .andDo(^(NSInvocation *inv) {
- // On first calculateLayoutThatFits, schedule our injected main thread work.
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- dispatch_async(dispatch_get_main_queue(), ^{
- injectedMainThreadWork();
- });
- });
- });
- }];
- }
-
- // The code in this section is designed to move in time order, all on the main thread:
-
- OCMExpect([nodeA.mock animateLayoutTransition:OCMOCK_ANY]).onMainThread();
- OCMExpect([nodeA.mock didCompleteLayoutTransition:OCMOCK_ANY]).onMainThread();
-
- // Trigger the layout transition.
- __block dispatch_block_t measurementCompletionBlock = nil;
- [nodeA transitionLayoutWithAnimation:NO shouldMeasureAsync:YES measurementCompletion:^{
- measurementCompletionBlock();
- }];
-
- // This block will get run after bg layout calculate starts, but before measurementCompletion
- __block BOOL injectedMainThreadWorkDone = NO;
- injectedMainThreadWork = ^{
- injectedMainThreadWorkDone = YES;
-
- [window layoutIfNeeded];
-
- // Ensure we're still on the old layout. We should stay on this until the transition completes.
- [self verifyFixture:fixture1];
- };
-
- measurementCompletionBlock = ^{
- XCTAssert(injectedMainThreadWorkDone, @"We hoped to get onto the main thread before the measurementCompletion callback ran.");
- };
-
- for (ASLayoutTestNode *node in allNodes) {
- OCMVerifyAllWithDelay(node.mock, verifyDelay);
- }
-
- [self verifyFixture:fixture2];
-}
-
-/**
- * Transition from fixture1 to Fixture2 on node A.
- *
- * Expect A and D to calculate once on main, and
- * to receive calculatedLayoutDidChange on main,
- * then to get animateLayoutTransition: and didCompleteLayoutTransition: on main.
- */
-- (void)testLayoutTransitionWithSyncMeasurement
-{
- [self stubCalculatedLayoutDidChange];
-
- // Precondition
- XCTAssertFalse(CGSizeEqualToSize(fixture5.layout.size, fixture1.layout.size));
-
- // First, apply fixture 5 and run a measurement pass, but don't run a layout pass
- // After this step, nodes will have pending layouts that are not yet applied
- [fixture5 apply];
- [fixture5 withSizeRangesForAllNodesUsingBlock:^(ASLayoutTestNode * _Nonnull node, ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange])
- .onMainThread();
- }];
-
- [nodeA layoutThatFits:ASSizeRangeMake(fixture5.layout.size)];
-
- // Assert that node A has layout size and size range from fixture 5
- XCTAssertTrue(CGSizeEqualToSize(fixture5.layout.size, nodeA.calculatedSize));
- XCTAssertTrue(ASSizeRangeEqualToSizeRange([fixture5 firstSizeRangeForNode:nodeA], nodeA.constrainedSizeForCalculatedLayout));
-
- // Then switch to fixture 1 and kick off a synchronous layout transition
- // Unapplied pending layouts from the previous measurement pass will be outdated
- [fixture1 apply];
- [fixture1 withSizeRangesForAllNodesUsingBlock:^(ASLayoutTestNode * _Nonnull node, ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange])
- .onMainThread();
- }];
-
- OCMExpect([nodeA.mock animateLayoutTransition:OCMOCK_ANY]).onMainThread();
- OCMExpect([nodeA.mock didCompleteLayoutTransition:OCMOCK_ANY]).onMainThread();
-
- [nodeA transitionLayoutWithAnimation:NO shouldMeasureAsync:NO measurementCompletion:nil];
-
- // Assert that node A picks up new layout size and size range from fixture 1
- XCTAssertTrue(CGSizeEqualToSize(fixture1.layout.size, nodeA.calculatedSize));
- XCTAssertTrue(ASSizeRangeEqualToSizeRange([fixture1 firstSizeRangeForNode:nodeA], nodeA.constrainedSizeForCalculatedLayout));
-
- [window layoutIfNeeded];
- [self verifyFixture:fixture1];
-}
-
-/**
- * Start at fixture 1.
- * Trigger an async transition to fixture 2.
- * While it's measuring, on main switch to fixture 4 (setNeedsLayout A, D) and run a CA layout pass.
- *
- * Correct behavior, we end up at fixture 4 since it's newer.
- * Current incorrect behavior, we end up at fixture 2 and we remeasure surviving node C.
- * Note: incorrect behavior likely introduced by the early check in __layout added in
- * https://github.com/facebookarchive/AsyncDisplayKit/pull/2657
- */
-- (void)DISABLE_testASetNeedsLayoutInterferingWithTheCurrentTransition
-{
- static BOOL enforceCorrectBehavior = NO;
-
- [self stubCalculatedLayoutDidChange];
- [self runFirstLayoutPassWithFixture:fixture1];
-
- [fixture2 apply];
-
- // Expect A, C, E to calculate new layouts off-main
- // dispatch_once onto main to run our injectedMainThread work while the transition calculates.
- __block dispatch_block_t injectedMainThreadWork = nil;
- for (ASLayoutTestNode *node in @[ nodeA, nodeC, nodeE ]) {
- [fixture2 withSizeRangesForNode:node block:^(ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange])
- .offMainThread()
- .andDo(^(NSInvocation *inv) {
- // On first calculateLayoutThatFits, schedule our injected main thread work.
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- dispatch_async(dispatch_get_main_queue(), ^{
- injectedMainThreadWork();
- });
- });
- });
- }];
- }
-
- // The code in this section is designed to move in time order, all on the main thread:
-
- // With the current behavior, the transition will continue and complete.
- if (!enforceCorrectBehavior) {
- OCMExpect([nodeA.mock animateLayoutTransition:OCMOCK_ANY]).onMainThread();
- OCMExpect([nodeA.mock didCompleteLayoutTransition:OCMOCK_ANY]).onMainThread();
- }
-
- // Trigger the layout transition.
- __block dispatch_block_t measurementCompletionBlock = nil;
- [nodeA transitionLayoutWithAnimation:NO shouldMeasureAsync:YES measurementCompletion:^{
- measurementCompletionBlock();
- }];
-
- // Injected block will get run on main after bg layout calculate starts, but before measurementCompletion
- __block BOOL injectedMainThreadWorkDone = NO;
- injectedMainThreadWork = ^{
- as_log_verbose(OS_LOG_DEFAULT, "Begin injectedMainThreadWork");
- injectedMainThreadWorkDone = YES;
-
- [fixture4 apply];
- as_log_verbose(OS_LOG_DEFAULT, "Did apply new fixture");
-
- if (enforceCorrectBehavior) {
- // Correct measurement behavior here is unclear, may depend on whether the layouts which
- // are common to both fixture2 and fixture4 are available from the cache.
- } else {
- // Incorrect behavior: nodeC will get measured against its new bounds on main.
- const auto cPendingSize = [fixture2 layoutForNode:nodeC].size;
- OCMExpect([nodeC.mock calculateLayoutThatFits:ASSizeRangeMake(cPendingSize)]).onMainThread();
- }
- [window layoutIfNeeded];
- as_log_verbose(OS_LOG_DEFAULT, "End injectedMainThreadWork");
- };
-
- measurementCompletionBlock = ^{
- XCTAssert(injectedMainThreadWorkDone, @"We hoped to get onto the main thread before the measurementCompletion callback ran.");
- };
-
- for (ASLayoutTestNode *node in allNodes) {
- OCMVerifyAllWithDelay(node.mock, verifyDelay);
- }
-
- // Incorrect behavior: The transition will "win" even though its transitioning to stale data.
- if (enforceCorrectBehavior) {
- [self verifyFixture:fixture4];
- } else {
- [self verifyFixture:fixture2];
- }
-}
-
-/**
- * Start on fixture 3 where nodeB is force-shrunk via multipass layout.
- * Apply fixture 1, which just changes nodeB's size and calls -setNeedsLayout on it.
- *
- * This behavior is currently broken. See implementation for correct behavior and incorrect behavior.
- */
-- (void)testCallingSetNeedsLayoutOnANodeThatWasSubjectToMultipassLayout
-{
- static BOOL const enforceCorrectBehavior = NO;
- [self stubCalculatedLayoutDidChange];
- [self runFirstLayoutPassWithFixture:fixture3];
-
- // Switch to fixture 1, updating nodeB's desired size and calling -setNeedsLayout
- // Now nodeB will fit happily into the stack.
- [fixture1 apply];
-
- if (enforceCorrectBehavior) {
- /*
- * Correct behavior: nodeB is remeasured against the first (unconstrained) size
- * and when it's discovered that now nodeB fits, nodeA will re-layout and we'll
- * end up correctly at fixture1.
- */
- OCMExpect([nodeB.mock calculateLayoutThatFits:[fixture3 firstSizeRangeForNode:nodeB]]);
-
- [fixture1 withSizeRangesForNode:nodeA block:^(ASSizeRange sizeRange) {
- OCMExpect([nodeA.mock calculateLayoutThatFits:sizeRange]);
- }];
-
- [window layoutIfNeeded];
- [self verifyFixture:fixture1];
- } else {
- /*
- * Incorrect behavior: nodeB is remeasured against the second (fixed-width) constraint.
- * The returned value (8) is clamped to the fixed with (7), and then compared to the previous
- * width (7) and we decide not to propagate up the invalidation, and we stay stuck on the old
- * layout (fixture3).
- */
- OCMExpect([nodeB.mock calculateLayoutThatFits:nodeB.constrainedSizeForCalculatedLayout]);
- [window layoutIfNeeded];
- [self verifyFixture:fixture3];
- }
-}
-
-#pragma mark - Helpers
-
-- (void)verifyFixture:(ASTLayoutFixture *)fixture
-{
- const auto expected = fixture.layout;
-
- // Ensure expected == frames
- const auto frames = [fixture.rootNode currentLayoutBasedOnFrames];
- if (![expected isEqual:frames]) {
- XCTFail(@"\n*** Layout verification failed – frames don't match expected. ***\nGot:\n%@\nExpected:\n%@", [frames recursiveDescription], [expected recursiveDescription]);
- }
-
- // Ensure expected == calculatedLayout
- const auto calculated = fixture.rootNode.calculatedLayout;
- if (![expected isEqual:calculated]) {
- XCTFail(@"\n*** Layout verification failed – calculated layout doesn't match expected. ***\nGot:\n%@\nExpected:\n%@", [calculated recursiveDescription], [expected recursiveDescription]);
- }
-}
-
-/**
- * Stubs calculatedLayoutDidChange for all nodes.
- *
- * It's not really a core layout engine method, and it's also
- * currently bugged and gets called a lot so for most
- * tests its better not to have expectations about it littered around.
- * https://github.com/TextureGroup/Texture/issues/422
- */
-- (void)stubCalculatedLayoutDidChange
-{
- stubbedCalculatedLayoutDidChange = YES;
- for (ASLayoutTestNode *node in allNodes) {
- OCMStub([node.mock calculatedLayoutDidChange]);
- }
-}
-
-/**
- * Fixture 1: A basic horizontal stack, all single-pass.
- *
- * [A: HorizStack([B, C, D])]. A is (10x1), B is (1x1), C is (2x1), D is (1x1)
- */
-- (ASTLayoutFixture *)createFixture1
-{
- const auto fixture = [[ASTLayoutFixture alloc] init];
-
- // nodeB
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeB];
- const auto layoutB = [ASLayout layoutWithLayoutElement:nodeB size:{1,1} position:{0,0} sublayouts:nil];
-
- // nodeC
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeC];
- const auto layoutC = [ASLayout layoutWithLayoutElement:nodeC size:{2,1} position:{4,0} sublayouts:nil];
-
- // nodeD
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeD];
- const auto layoutD = [ASLayout layoutWithLayoutElement:nodeD size:{1,1} position:{9,0} sublayouts:nil];
-
- [fixture addSizeRange:{{10, 1}, {10, 1}} forNode:nodeA];
- const auto layoutA = [ASLayout layoutWithLayoutElement:nodeA size:{10,1} position:ASPointNull sublayouts:@[ layoutB, layoutC, layoutD ]];
- fixture.layout = layoutA;
-
- [fixture.layoutSpecBlocks setObject:fixture1and3and5NodeALayoutSpecBlock forKey:nodeA];
- return fixture;
-}
-
-/**
- * Fixture 2: A simple transition away from fixture 1.
- *
- * [A: HorizStack([B, C, E])]. A is (10x1), B is (1x1), C is (4x1), E is (1x1)
- *
- * From fixture 1:
- * B survives with same layout
- * C survives with new layout
- * D is removed
- * E joins with first layout
- */
-- (ASTLayoutFixture *)createFixture2
-{
- const auto fixture = [[ASTLayoutFixture alloc] init];
-
- // nodeB
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeB];
- const auto layoutB = [ASLayout layoutWithLayoutElement:nodeB size:{1,1} position:{0,0} sublayouts:nil];
-
- // nodeC
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeC];
- const auto layoutC = [ASLayout layoutWithLayoutElement:nodeC size:{4,1} position:{3,0} sublayouts:nil];
-
- // nodeE
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeE];
- const auto layoutE = [ASLayout layoutWithLayoutElement:nodeE size:{1,1} position:{9,0} sublayouts:nil];
-
- [fixture addSizeRange:{{10, 1}, {10, 1}} forNode:nodeA];
- const auto layoutA = [ASLayout layoutWithLayoutElement:nodeA size:{10,1} position:ASPointNull sublayouts:@[ layoutB, layoutC, layoutE ]];
- fixture.layout = layoutA;
-
- ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeE ]];
- };
- [fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA];
- return fixture;
-}
-
-/**
- * Fixture 3: Multipass stack layout
- *
- * [A: HorizStack([B, C, D])]. A is (10x1), B is (7x1), C is (2x1), D is (1x1)
- *
- * nodeB (which has flexShrink=1) will return 8x1 for its size during the first
- * stack pass, and it'll be subject to a second pass where it returns 7x1.
- *
- */
-- (ASTLayoutFixture *)createFixture3
-{
- const auto fixture = [[ASTLayoutFixture alloc] init];
-
- // nodeB wants 8,1 but it will settle for 7,1
- [fixture setReturnedSize:{8,1} forNode:nodeB];
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeB];
- [fixture addSizeRange:{{7, 0}, {7, 1}} forNode:nodeB];
- const auto layoutB = [ASLayout layoutWithLayoutElement:nodeB size:{7,1} position:{0,0} sublayouts:nil];
-
- // nodeC
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeC];
- const auto layoutC = [ASLayout layoutWithLayoutElement:nodeC size:{2,1} position:{7,0} sublayouts:nil];
-
- // nodeD
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeD];
- const auto layoutD = [ASLayout layoutWithLayoutElement:nodeD size:{1,1} position:{9,0} sublayouts:nil];
-
- [fixture addSizeRange:{{10, 1}, {10, 1}} forNode:nodeA];
- const auto layoutA = [ASLayout layoutWithLayoutElement:nodeA size:{10,1} position:ASPointNull sublayouts:@[ layoutB, layoutC, layoutD ]];
- fixture.layout = layoutA;
-
- [fixture.layoutSpecBlocks setObject:fixture1and3and5NodeALayoutSpecBlock forKey:nodeA];
- return fixture;
-}
-
-/**
- * Fixture 4: A different simple transition away from fixture 1.
- *
- * [A: HorizStack([B, D, E])]. A is (10x1), B is (1x1), D is (2x1), E is (1x1)
- *
- * From fixture 1:
- * B survives with same layout
- * C is removed
- * D survives with new layout
- * E joins with first layout
- *
- * From fixture 2:
- * B survives with same layout
- * C is removed
- * D joins with first layout
- * E survives with same layout
- */
-- (ASTLayoutFixture *)createFixture4
-{
- const auto fixture = [[ASTLayoutFixture alloc] init];
-
- // nodeB
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeB];
- const auto layoutB = [ASLayout layoutWithLayoutElement:nodeB size:{1,1} position:{0,0} sublayouts:nil];
-
- // nodeD
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeD];
- const auto layoutD = [ASLayout layoutWithLayoutElement:nodeD size:{2,1} position:{4,0} sublayouts:nil];
-
- // nodeE
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeE];
- const auto layoutE = [ASLayout layoutWithLayoutElement:nodeE size:{1,1} position:{9,0} sublayouts:nil];
-
- [fixture addSizeRange:{{10, 1}, {10, 1}} forNode:nodeA];
- const auto layoutA = [ASLayout layoutWithLayoutElement:nodeA size:{10,1} position:ASPointNull sublayouts:@[ layoutB, layoutD, layoutE ]];
- fixture.layout = layoutA;
-
- ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
- return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeD, nodeE ]];
- };
- [fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA];
- return fixture;
-}
-
-/**
- * Fixture 5: Same as fixture 1, but with a bigger root node (node A).
- *
- * [A: HorizStack([B, C, D])]. A is (15x1), B is (1x1), C is (2x1), D is (1x1)
- */
-- (ASTLayoutFixture *)createFixture5
-{
- const auto fixture = [[ASTLayoutFixture alloc] init];
-
- // nodeB
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeB];
- const auto layoutB = [ASLayout layoutWithLayoutElement:nodeB size:{1,1} position:{0,0} sublayouts:nil];
-
- // nodeC
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeC];
- const auto layoutC = [ASLayout layoutWithLayoutElement:nodeC size:{2,1} position:{4,0} sublayouts:nil];
-
- // nodeD
- [fixture addSizeRange:{{0, 0}, {INFINITY, 1}} forNode:nodeD];
- const auto layoutD = [ASLayout layoutWithLayoutElement:nodeD size:{1,1} position:{9,0} sublayouts:nil];
-
- [fixture addSizeRange:{{15, 1}, {15, 1}} forNode:nodeA];
- const auto layoutA = [ASLayout layoutWithLayoutElement:nodeA size:{15,1} position:ASPointNull sublayouts:@[ layoutB, layoutC, layoutD ]];
- fixture.layout = layoutA;
-
- [fixture.layoutSpecBlocks setObject:fixture1and3and5NodeALayoutSpecBlock forKey:nodeA];
- return fixture;
-}
-
-- (void)runFirstLayoutPassWithFixture:(ASTLayoutFixture *)fixture
-{
- [fixture apply];
- [fixture withSizeRangesForAllNodesUsingBlock:^(ASLayoutTestNode * _Nonnull node, ASSizeRange sizeRange) {
- OCMExpect([node.mock calculateLayoutThatFits:sizeRange]).onMainThread();
-
- if (!stubbedCalculatedLayoutDidChange) {
- OCMExpect([node.mock calculatedLayoutDidChange]).onMainThread();
- }
- }];
-
- // Trigger CA layout pass.
- [window layoutIfNeeded];
-
- // Make sure it went through.
- [self verifyFixture:fixture];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutFlatteningTests.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutFlatteningTests.mm
deleted file mode 100644
index 0a1fa02261..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutFlatteningTests.mm
+++ /dev/null
@@ -1,206 +0,0 @@
-//
-// ASLayoutFlatteningTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-
-@interface ASLayoutFlatteningTests : XCTestCase
-@end
-
-@implementation ASLayoutFlatteningTests
-
-static ASLayout *layoutWithCustomPosition(CGPoint position, id element, NSArray *sublayouts)
-{
- return [ASLayout layoutWithLayoutElement:element
- size:CGSizeMake(100, 100)
- position:position
- sublayouts:sublayouts];
-}
-
-static ASLayout *layout(id element, NSArray *sublayouts)
-{
- return layoutWithCustomPosition(CGPointZero, element, sublayouts);
-}
-
-- (void)testThatFlattenedLayoutContainsOnlyDirectSubnodesInValidOrder
-{
- ASLayout *flattenedLayout;
-
- @autoreleasepool {
- NSMutableArray *subnodes = [NSMutableArray array];
- NSMutableArray *layoutSpecs = [NSMutableArray array];
- NSMutableArray *indirectSubnodes = [NSMutableArray array];
-
- ASDisplayNode *(^subnode)(void) = ^ASDisplayNode *() { [subnodes addObject:[[ASDisplayNode alloc] init]]; return [subnodes lastObject]; };
- ASLayoutSpec *(^layoutSpec)(void) = ^ASLayoutSpec *() { [layoutSpecs addObject:[[ASLayoutSpec alloc] init]]; return [layoutSpecs lastObject]; };
- ASDisplayNode *(^indirectSubnode)(void) = ^ASDisplayNode *() { [indirectSubnodes addObject:[[ASDisplayNode alloc] init]]; return [indirectSubnodes lastObject]; };
-
- NSArray *sublayouts = @[
- layout(subnode(), @[
- layout(indirectSubnode(), @[]),
- ]),
- layout(layoutSpec(), @[
- layout(subnode(), @[]),
- layout(layoutSpec(), @[
- layout(layoutSpec(), @[]),
- layout(subnode(), @[]),
- ]),
- layout(layoutSpec(), @[]),
- ]),
- layout(layoutSpec(), @[
- layout(subnode(), @[
- layout(indirectSubnode(), @[]),
- layout(indirectSubnode(), @[
- layout(indirectSubnode(), @[])
- ]),
- ])
- ]),
- layout(subnode(), @[]),
- ];
-
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- ASLayout *originalLayout = [ASLayout layoutWithLayoutElement:rootNode
- size:CGSizeMake(1000, 1000)
- sublayouts:sublayouts];
- flattenedLayout = [originalLayout filteredNodeLayoutTree];
- NSArray *flattenedSublayouts = flattenedLayout.sublayouts;
- NSUInteger sublayoutsCount = flattenedSublayouts.count;
-
- XCTAssertEqualObjects(originalLayout.layoutElement, flattenedLayout.layoutElement, @"The root node should be reserved");
- XCTAssertTrue(ASPointIsNull(flattenedLayout.position), @"Position of the root layout should be null");
- XCTAssertEqual(subnodes.count, sublayoutsCount, @"Flattened layout should only contain direct subnodes");
- for (int i = 0; i < sublayoutsCount; i++) {
- XCTAssertEqualObjects(subnodes[i], flattenedSublayouts[i].layoutElement, @"Sublayouts should be in correct order (flattened in DFS fashion)");
- }
- }
-
- for (ASLayout *sublayout in flattenedLayout.sublayouts) {
- XCTAssertNotNil(sublayout.layoutElement, @"Sublayout elements should be retained");
- XCTAssertEqual(0, sublayout.sublayouts.count, @"Sublayouts should not have their own sublayouts");
- }
-}
-
-#pragma mark - Test reusing ASLayouts while flattening
-
-- (void)testThatLayoutWithNonNullPositionIsNotReused
-{
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- ASLayout *originalLayout = layoutWithCustomPosition(CGPointMake(10, 10), rootNode, @[]);
- ASLayout *flattenedLayout = [originalLayout filteredNodeLayoutTree];
- XCTAssertNotEqualObjects(originalLayout, flattenedLayout, "@Layout should be reused");
- XCTAssertTrue(ASPointIsNull(flattenedLayout.position), @"Position of a root layout should be null");
-}
-
-- (void)testThatLayoutWithNullPositionAndNoSublayoutIsReused
-{
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- ASLayout *originalLayout = layoutWithCustomPosition(ASPointNull, rootNode, @[]);
- ASLayout *flattenedLayout = [originalLayout filteredNodeLayoutTree];
- XCTAssertEqualObjects(originalLayout, flattenedLayout, "@Layout should be reused");
- XCTAssertTrue(ASPointIsNull(flattenedLayout.position), @"Position of a root layout should be null");
-}
-
-- (void)testThatLayoutWithNullPositionAndFlattenedNodeSublayoutsIsReused
-{
- ASLayout *flattenedLayout;
-
- @autoreleasepool {
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- NSMutableArray *subnodes = [NSMutableArray array];
- ASDisplayNode *(^subnode)(void) = ^ASDisplayNode *() { [subnodes addObject:[[ASDisplayNode alloc] init]]; return [subnodes lastObject]; };
- ASLayout *originalLayout = layoutWithCustomPosition(ASPointNull,
- rootNode,
- @[
- layoutWithCustomPosition(CGPointMake(10, 10), subnode(), @[]),
- layoutWithCustomPosition(CGPointMake(20, 20), subnode(), @[]),
- layoutWithCustomPosition(CGPointMake(30, 30), subnode(), @[]),
- ]);
- flattenedLayout = [originalLayout filteredNodeLayoutTree];
- XCTAssertEqualObjects(originalLayout, flattenedLayout, "@Layout should be reused");
- XCTAssertTrue(ASPointIsNull(flattenedLayout.position), @"Position of the root layout should be null");
- }
-
- for (ASLayout *sublayout in flattenedLayout.sublayouts) {
- XCTAssertNotNil(sublayout.layoutElement, @"Sublayout elements should be retained");
- XCTAssertEqual(0, sublayout.sublayouts.count, @"Sublayouts should not have their own sublayouts");
- }
-}
-
-- (void)testThatLayoutWithNullPositionAndUnflattenedSublayoutsIsNotReused
-{
- ASLayout *flattenedLayout;
-
- @autoreleasepool {
- ASDisplayNode *rootNode = [[ASDisplayNode alloc] init];
- NSMutableArray *subnodes = [NSMutableArray array];
- NSMutableArray *layoutSpecs = [NSMutableArray array];
- NSMutableArray *indirectSubnodes = [NSMutableArray array];
- NSMutableArray *reusedLayouts = [NSMutableArray array];
-
- ASDisplayNode *(^subnode)(void) = ^ASDisplayNode *() { [subnodes addObject:[[ASDisplayNode alloc] init]]; return [subnodes lastObject]; };
- ASLayoutSpec *(^layoutSpec)(void) = ^ASLayoutSpec *() { [layoutSpecs addObject:[[ASLayoutSpec alloc] init]]; return [layoutSpecs lastObject]; };
- ASDisplayNode *(^indirectSubnode)(void) = ^ASDisplayNode *() { [indirectSubnodes addObject:[[ASDisplayNode alloc] init]]; return [indirectSubnodes lastObject]; };
- ASLayout *(^reusedLayout)(ASDisplayNode *) = ^ASLayout *(ASDisplayNode *subnode) { [reusedLayouts addObject:layout(subnode, @[])]; return [reusedLayouts lastObject]; };
-
- /*
- * Layouts with sublayouts of both nodes and layout specs should not be reused.
- * However, all flattened node sublayouts with valid position should be reused.
- */
- ASLayout *originalLayout = layoutWithCustomPosition(ASPointNull,
- rootNode,
- @[
- reusedLayout(subnode()),
- // The 2 node sublayouts below should be reused although they are in a layout spec sublayout.
- // That is because each of them have an absolute position of zero.
- // This case can happen, for example, as the result of a background/overlay layout spec.
- layout(layoutSpec(), @[
- reusedLayout(subnode()),
- reusedLayout(subnode())
- ]),
- layout(subnode(), @[
- layout(layoutSpec(), @[])
- ]),
- layout(subnode(), @[
- layout(indirectSubnode(), @[])
- ]),
- layoutWithCustomPosition(CGPointMake(10, 10), subnode(), @[]),
- // The 2 node sublayouts below shouldn't be reused because they have non-zero absolute positions.
- layoutWithCustomPosition(CGPointMake(20, 20), layoutSpec(), @[
- layout(subnode(), @[]),
- layout(subnode(), @[])
- ]),
- ]);
- flattenedLayout = [originalLayout filteredNodeLayoutTree];
- NSArray *flattenedSublayouts = flattenedLayout.sublayouts;
- NSUInteger sublayoutsCount = flattenedSublayouts.count;
-
- XCTAssertNotEqualObjects(originalLayout, flattenedLayout, @"Original layout should not be reused");
- XCTAssertEqualObjects(originalLayout.layoutElement, flattenedLayout.layoutElement, @"The root node should be reserved");
- XCTAssertTrue(ASPointIsNull(flattenedLayout.position), @"Position of the root layout should be null");
- XCTAssertTrue(reusedLayouts.count <= sublayoutsCount, @"Some sublayouts can't be reused");
- XCTAssertEqual(subnodes.count, sublayoutsCount, @"Flattened layout should only contain direct subnodes");
- int numOfActualReusedLayouts = 0;
- for (int i = 0; i < sublayoutsCount; i++) {
- ASLayout *sublayout = flattenedSublayouts[i];
- XCTAssertEqualObjects(subnodes[i], sublayout.layoutElement, @"Sublayouts should be in correct order (flattened in DFS fashion)");
- if ([reusedLayouts containsObject:sublayout]) {
- numOfActualReusedLayouts++;
- }
- }
- XCTAssertEqual(numOfActualReusedLayouts, reusedLayouts.count, @"Should reuse all layouts that can be reused");
- }
-
- for (ASLayout *sublayout in flattenedLayout.sublayouts) {
- XCTAssertNotNil(sublayout.layoutElement, @"Sublayout elements should be retained");
- XCTAssertEqual(0, sublayout.sublayouts.count, @"Sublayouts should not have their own sublayouts");
- }
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.h b/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.h
deleted file mode 100644
index 740017ee9e..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// ASLayoutSpecSnapshotTestsHelper.h
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASSnapshotTestCase.h"
-#import
-
-@class ASLayoutSpec;
-
-@interface ASLayoutSpecSnapshotTestCase: ASSnapshotTestCase
-/**
- Test the layout spec or records a snapshot if recordMode is YES.
- @param layoutSpec The layout spec under test or to snapshot
- @param sizeRange The size range used to calculate layout of the given layout spec.
- @param subnodes An array of ASDisplayNodes used within the layout spec.
- @param identifier An optional identifier, used to identify this snapshot test.
-
- @discussion In order to make the layout spec visible, it is embeded to a ASDisplayNode host.
- Any subnodes used within the layout spec must be provided.
- They will be added to the host in the same order as the array.
- */
-- (void)testLayoutSpec:(ASLayoutSpec *)layoutSpec
- sizeRange:(ASSizeRange)sizeRange
- subnodes:(NSArray *)subnodes
- identifier:(NSString *)identifier;
-@end
-
-__attribute__((overloadable)) static inline ASDisplayNode *ASDisplayNodeWithBackgroundColor(UIColor *backgroundColor, CGSize size) {
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.layerBacked = YES;
- node.backgroundColor = backgroundColor;
- node.style.width = ASDimensionMakeWithPoints(size.width);
- node.style.height = ASDimensionMakeWithPoints(size.height);
- return node;
-}
-
-__attribute__((overloadable)) static inline ASDisplayNode *ASDisplayNodeWithBackgroundColor(UIColor *backgroundColor)
-{
- return ASDisplayNodeWithBackgroundColor(backgroundColor, CGSizeZero);
-}
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.mm
deleted file mode 100644
index dec82d4c39..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecSnapshotTestsHelper.mm
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// ASLayoutSpecSnapshotTestsHelper.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-#import
-#import
-
-@interface ASTestNode : ASDisplayNode
-@property (nonatomic, nullable) ASLayoutSpec *layoutSpecUnderTest;
-@end
-
-@implementation ASLayoutSpecSnapshotTestCase
-
-- (void)setUp
-{
- [super setUp];
- self.recordMode = NO;
-}
-
-- (void)testLayoutSpec:(ASLayoutSpec *)layoutSpec
- sizeRange:(ASSizeRange)sizeRange
- subnodes:(NSArray *)subnodes
- identifier:(NSString *)identifier
-{
- ASTestNode *node = [[ASTestNode alloc] init];
-
- for (ASDisplayNode *subnode in subnodes) {
- [node addSubnode:subnode];
- }
-
- node.layoutSpecUnderTest = layoutSpec;
-
- ASDisplayNodeSizeToFitSizeRange(node, sizeRange);
- ASSnapshotVerifyNode(node, identifier);
-}
-
-@end
-
-@implementation ASTestNode
-- (instancetype)init
-{
- if (self = [super init]) {
- self.layerBacked = YES;
- }
- return self;
-}
-
-- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
-{
- return _layoutSpecUnderTest;
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecTests.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutSpecTests.mm
deleted file mode 100644
index ff13b66553..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutSpecTests.mm
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// ASLayoutSpecTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-#import
-
-#pragma mark - ASDKExtendedLayoutSpec
-
-/*
- * Extend the ASDKExtendedLayoutElement
- * It adds a
- * - primitive / CGFloat (extendedWidth)
- * - struct / ASDimension (extendedDimension)
- * - primitive / ASStackLayoutDirection (extendedDirection)
- */
-@protocol ASDKExtendedLayoutElement
-@property (nonatomic) CGFloat extendedWidth;
-@property (nonatomic) ASDimension extendedDimension;
-@property (copy, nonatomic) NSString *extendedName;
-@end
-
-/*
- * Let the ASLayoutElementStyle conform to the ASDKExtendedLayoutElement protocol and add properties implementation
- */
-@interface ASLayoutElementStyle (ASDKExtendedLayoutElement)
-@end
-
-@implementation ASLayoutElementStyle (ASDKExtendedLayoutElement)
-ASDK_STYLE_PROP_PRIM(CGFloat, extendedWidth, setExtendedWidth, 0);
-ASDK_STYLE_PROP_STR(ASDimension, extendedDimension, setExtendedDimension, ASDimensionMake(ASDimensionUnitAuto, 0));
-ASDK_STYLE_PROP_OBJ(NSString *, extendedName, setExtendedName);
-@end
-
-/*
- * As the ASLayoutElementStyle conforms to the ASDKExtendedLayoutElement protocol now, ASDKExtendedLayoutElement properties
- * can be accessed in ASDKExtendedLayoutSpec
- */
-@interface ASDKExtendedLayoutSpec : ASLayoutSpec
-@end
-
-@implementation ASDKExtendedLayoutSpec
-
-- (void)doSetSomeStyleValuesToChildren
-{
- for (id child in self.children) {
- child.style.extendedWidth = 100;
- child.style.extendedDimension = ASDimensionMake(100);
- child.style.extendedName = @"ASDK";
- }
-}
-
-- (void)doUseSomeStyleValuesFromChildren
-{
- for (id child in self.children) {
- __unused CGFloat extendedWidth = child.style.extendedWidth;
- __unused ASDimension extendedDimension = child.style.extendedDimension;
- __unused NSString *extendedName = child.style.extendedName;
- }
-}
-
-@end
-
-
-#pragma mark - ASLayoutSpecTests
-
-@interface ASLayoutSpecTests : XCTestCase
-
-@end
-
-@implementation ASLayoutSpecTests
-
-- (void)testSetPrimitiveToExtendedStyle
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.style.extendedWidth = 100;
- XCTAssert(node.style.extendedWidth == 100, @"Primitive value should be set on extended style");
-}
-
-- (void)testSetStructToExtendedStyle
-{
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.style.extendedDimension = ASDimensionMake(100);
- XCTAssertTrue(ASDimensionEqualToDimension(node.style.extendedDimension, ASDimensionMake(100)), @"Struct should be set on extended style");
-}
-
-- (void)testSetObjectToExtendedStyle
-{
- NSString *extendedName = @"ASDK";
-
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.style.extendedName = extendedName;
- XCTAssertEqualObjects(node.style.extendedName, extendedName, @"Object should be set on extended style");
-}
-
-
-- (void)testUseOfExtendedStyleProperties
-{
- ASDKExtendedLayoutSpec *extendedLayoutSpec = [ASDKExtendedLayoutSpec new];
- extendedLayoutSpec.children = @[[[ASDisplayNode alloc] init], [[ASDisplayNode alloc] init]];
- XCTAssertNoThrow([extendedLayoutSpec doSetSomeStyleValuesToChildren]);
- XCTAssertNoThrow([extendedLayoutSpec doUseSomeStyleValuesFromChildren]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.h b/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.h
deleted file mode 100644
index 231447abe1..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// ASLayoutTestNode.h
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-@interface ASLayoutTestNode : ASDisplayNode
-
-/**
- * Mocking ASDisplayNodes directly isn't very safe because when you pump mock objects
- * into the guts of the framework, bad things happen e.g. direct-ivar-access on mock
- * objects will return garbage data.
- *
- * Instead we create a strict mock for each node, and forward a selected set of calls to it.
- */
-@property (nonatomic, readonly) id mock;
-
-/**
- * The size that this node will return in calculateLayoutThatFits (if it doesn't have a layoutSpecBlock).
- *
- * Changing this value will call -setNeedsLayout on the node.
- */
-@property (nonatomic) CGSize testSize;
-
-/**
- * Generate a layout based on the frame of this node and its subtree.
- *
- * The root layout will be unpositioned. This is so that the returned layout can be directly
- * compared to `calculatedLayout`
- */
-- (ASLayout *)currentLayoutBasedOnFrames;
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.mm b/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.mm
deleted file mode 100644
index 2805aa36c9..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASLayoutTestNode.mm
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// ASLayoutTestNode.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutTestNode.h"
-#import
-#import "OCMockObject+ASAdditions.h"
-
-@implementation ASLayoutTestNode
-
-- (instancetype)init
-{
- if (self = [super init]) {
- _mock = OCMStrictClassMock([ASDisplayNode class]);
-
- // If errors occur (e.g. unexpected method) we need to quickly figure out
- // which node is at fault, so we inject the node name into the mock instance
- // description.
- __weak __typeof(self) weakSelf = self;
- [_mock setModifyDescriptionBlock:^(id mock, NSString *baseDescription){
- return [NSString stringWithFormat:@"Mock(%@)", weakSelf.description];
- }];
- }
- return self;
-}
-
-- (ASLayout *)currentLayoutBasedOnFrames
-{
- return [self _currentLayoutBasedOnFramesForRootNode:YES];
-}
-
-- (ASLayout *)_currentLayoutBasedOnFramesForRootNode:(BOOL)isRootNode
-{
- const auto sublayouts = [[NSMutableArray alloc] init];
- for (ASLayoutTestNode *subnode in self.subnodes) {
- [sublayouts addObject:[subnode _currentLayoutBasedOnFramesForRootNode:NO]];
- }
- CGPoint rootPosition = isRootNode ? ASPointNull : self.frame.origin;
- return [ASLayout layoutWithLayoutElement:self size:self.frame.size position:rootPosition sublayouts:sublayouts];
-}
-
-- (void)setTestSize:(CGSize)testSize
-{
- if (!CGSizeEqualToSize(testSize, _testSize)) {
- _testSize = testSize;
- [self setNeedsLayout];
- }
-}
-
-- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
-{
- [_mock calculateLayoutThatFits:constrainedSize];
-
- // If we have a layout spec block, or no test size, return super.
- if (self.layoutSpecBlock || CGSizeEqualToSize(self.testSize, CGSizeZero)) {
- return [super calculateLayoutThatFits:constrainedSize];
- } else {
- // Interestingly, the infra will auto-clamp sizes from calculateSizeThatFits, but not from calculateLayoutThatFits.
- const auto size = ASSizeRangeClamp(constrainedSize, self.testSize);
- return [ASLayout layoutWithLayoutElement:self size:size];
- }
-}
-
-#pragma mark - Forwarding to mock
-
-- (void)calculatedLayoutDidChange
-{
- [_mock calculatedLayoutDidChange];
- [super calculatedLayoutDidChange];
-}
-
-- (void)didCompleteLayoutTransition:(id)context
-{
- [_mock didCompleteLayoutTransition:context];
- [super didCompleteLayoutTransition:context];
-}
-
-- (void)animateLayoutTransition:(id)context
-{
- [_mock animateLayoutTransition:context];
- [super animateLayoutTransition:context];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASMultiplexImageNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASMultiplexImageNodeTests.mm
deleted file mode 100644
index caf86bb48e..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASMultiplexImageNodeTests.mm
+++ /dev/null
@@ -1,265 +0,0 @@
-//
-// ASMultiplexImageNodeTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import "NSInvocation+ASTestHelpers.h"
-
-#import
-#import
-#import
-
-#import
-
-@interface ASMultiplexImageNodeTests : XCTestCase
-{
-@private
- id mockCache;
- id mockDownloader;
- id mockDataSource;
- id mockDelegate;
- ASMultiplexImageNode *imageNode;
-}
-
-@end
-
-@implementation ASMultiplexImageNodeTests
-
-#pragma mark - Helpers.
-
-- (NSURL *)_testImageURL
-{
- return [[NSBundle bundleForClass:[self class]] URLForResource:@"logo-square"
- withExtension:@"png"
- subdirectory:@"TestResources"];
-}
-
-- (UIImage *)_testImage
-{
- return [UIImage imageWithContentsOfFile:[self _testImageURL].path];
-}
-
-#pragma mark - Unit tests.
-
-// TODO: add tests for delegate display notifications
-
-- (void)setUp
-{
- [super setUp];
-
- mockCache = OCMStrictProtocolMock(@protocol(ASImageCacheProtocol));
- [mockCache setExpectationOrderMatters:YES];
- mockDownloader = OCMStrictProtocolMock(@protocol(ASImageDownloaderProtocol));
- [mockDownloader setExpectationOrderMatters:YES];
- imageNode = [[ASMultiplexImageNode alloc] initWithCache:mockCache downloader:mockDownloader];
-
- mockDataSource = OCMStrictProtocolMock(@protocol(ASMultiplexImageNodeDataSource));
- [mockDataSource setExpectationOrderMatters:YES];
- imageNode.dataSource = mockDataSource;
-
- mockDelegate = OCMProtocolMock(@protocol(ASMultiplexImageNodeDelegate));
- [mockDelegate setExpectationOrderMatters:YES];
- imageNode.delegate = mockDelegate;
-}
-
-- (void)tearDown
-{
- OCMVerifyAll(mockDelegate);
- OCMVerifyAll(mockDataSource);
- OCMVerifyAll(mockDownloader);
- OCMVerifyAll(mockCache);
- [super tearDown];
-}
-
-- (void)testDataSourceImageMethod
-{
- NSNumber *imageIdentifier = @1;
-
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier])
- .andReturn([self _testImage]);
-
- imageNode.imageIdentifiers = @[imageIdentifier];
- [imageNode reloadImageIdentifierSources];
-
- // Also expect it to be loaded immediately.
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, imageIdentifier, @"imageIdentifier was not loaded");
- // And for the image to be equivalent to the image we provided.
- XCTAssertEqualObjects(UIImagePNGRepresentation(imageNode.image),
- UIImagePNGRepresentation([self _testImage]),
- @"Loaded image isn't the one we provided");
-}
-
-- (void)testDataSourceURLMethod
-{
- NSNumber *imageIdentifier = @1;
-
- // First expect to be hit for the image directly, and fail to return it.
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier])
- .andReturn((id)nil);
- // BUG: -imageForImageIdentifier is called twice in this case (where we return nil).
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier])
- .andReturn((id)nil);
- // Then expect to be hit for the URL, which we'll return.
- OCMExpect([mockDataSource multiplexImageNode:imageNode URLForImageIdentifier:imageIdentifier])
- .andReturn([self _testImageURL]);
-
- // Mock the cache to do a cache-hit for the test image URL.
- OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]])
- .andDo(^(NSInvocation *inv) {
- ASImageCacherCompletion completionBlock = [inv as_argumentAtIndexAsObject:4];
- completionBlock([self _testImage]);
- });
-
- imageNode.imageIdentifiers = @[imageIdentifier];
- // Kick off loading.
- [imageNode reloadImageIdentifierSources];
-
- // Also expect it to be loaded immediately.
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, imageIdentifier, @"imageIdentifier was not loaded");
- // And for the image to be equivalent to the image we provided.
- XCTAssertEqualObjects(UIImagePNGRepresentation(imageNode.image),
- UIImagePNGRepresentation([self _testImage]),
- @"Loaded image isn't the one we provided");
-}
-
-- (void)testAddLowerQualityImageIdentifier
-{
- // Adding a lower quality image identifier should not cause any loading.
- NSNumber *highResIdentifier = @2, *lowResIdentifier = @1;
-
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:highResIdentifier])
- .andReturn([self _testImage]);
- imageNode.imageIdentifiers = @[highResIdentifier];
- [imageNode reloadImageIdentifierSources];
-
- // At this point, we should have the high-res identifier loaded and the DS should have been hit once.
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
-
- // BUG: We should not get another -imageForImageIdentifier:highResIdentifier.
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:highResIdentifier])
- .andReturn([self _testImage]);
-
- imageNode.imageIdentifiers = @[highResIdentifier, lowResIdentifier];
- [imageNode reloadImageIdentifierSources];
-
- // At this point the high-res should still be loaded, and the data source should not have been hit again (see BUG above).
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
-}
-
-- (void)testAddHigherQualityImageIdentifier
-{
- NSNumber *lowResIdentifier = @1, *highResIdentifier = @2;
-
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:lowResIdentifier])
- .andReturn([self _testImage]);
-
- imageNode.imageIdentifiers = @[lowResIdentifier];
- [imageNode reloadImageIdentifierSources];
-
- // At this point, we should have the low-res identifier loaded and the DS should have been hit once.
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, lowResIdentifier, @"Low res identifier should be loaded.");
-
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:highResIdentifier])
- .andReturn([self _testImage]);
-
- imageNode.imageIdentifiers = @[highResIdentifier, lowResIdentifier];
- [imageNode reloadImageIdentifierSources];
-
- // At this point the high-res should be loaded, and the data source should been hit twice.
- XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
-}
-
-- (void)testIntermediateImageDownloading
-{
- imageNode.downloadsIntermediateImages = YES;
-
- // Let them call URLForImageIdentifier all they want.
- OCMStub([mockDataSource multiplexImageNode:imageNode URLForImageIdentifier:[OCMArg isNotNil]]);
-
- // Set up a few identifiers to load.
- NSInteger identifierCount = 5;
- NSMutableArray *imageIdentifiers = [NSMutableArray array];
- for (NSInteger identifier = identifierCount; identifier > 0; identifier--) {
- [imageIdentifiers addObject:@(identifier)];
- }
-
- // Create the array of IDs in the order we expect them to get -imageForImageIdentifier:
- // BUG: The second to last ID (the last one that returns nil) will get -imageForImageIdentifier: called
- // again after the last ID (the one that returns non-nil).
- id secondToLastID = imageIdentifiers[identifierCount - 2];
- NSArray *imageIdentifiersThatWillBeCalled = [imageIdentifiers arrayByAddingObject:secondToLastID];
-
- for (id imageID in imageIdentifiersThatWillBeCalled) {
- // Return nil for everything except the worst ID.
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageID])
- .andDo(^(NSInvocation *inv){
- id imageID = [inv as_argumentAtIndexAsObject:3];
- if ([imageID isEqual:imageIdentifiers.lastObject]) {
- [inv as_setReturnValueWithObject:[self _testImage]];
- } else {
- [inv as_setReturnValueWithObject:nil];
- }
- });
- }
-
- imageNode.imageIdentifiers = imageIdentifiers;
- [imageNode reloadImageIdentifierSources];
-}
-
-- (void)testUncachedDownload
-{
- // Mock a cache miss.
- OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]])
- .andDo(^(NSInvocation *inv){
- ASImageCacherCompletion completion = [inv as_argumentAtIndexAsObject:4];
- completion(nil);
- });
-
- // Mock a 50%-progress URL download.
- const CGFloat mockedProgress = 0.5;
- OCMExpect([mockDownloader downloadImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY downloadProgress:[OCMArg isNotNil] completion:[OCMArg isNotNil]])
- .andDo(^(NSInvocation *inv){
- // Simulate progress.
- ASImageDownloaderProgress progressBlock = [inv as_argumentAtIndexAsObject:4];
- progressBlock(mockedProgress);
-
- // Simulate completion.
- ASImageDownloaderCompletion completionBlock = [inv as_argumentAtIndexAsObject:5];
- completionBlock([self _testImage], nil, nil, nil);
- });
-
- NSNumber *imageIdentifier = @1;
-
- // Mock the data source to return nil image, and our test URL.
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier]);
- // BUG: Multiplex image node will call imageForImageIdentifier twice if we return nil.
- OCMExpect([mockDataSource multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier]);
- OCMExpect([mockDataSource multiplexImageNode:imageNode URLForImageIdentifier:imageIdentifier])
- .andReturn([self _testImageURL]);
-
- // Mock the delegate to expect start, 50% progress, and completion invocations.
- OCMExpect([mockDelegate multiplexImageNode:imageNode didStartDownloadOfImageWithIdentifier:imageIdentifier]);
- OCMExpect([mockDelegate multiplexImageNode:imageNode didUpdateDownloadProgress:mockedProgress forImageWithIdentifier:imageIdentifier]);
- OCMExpect([mockDelegate multiplexImageNode:imageNode didUpdateImage:[OCMArg isNotNil] withIdentifier:imageIdentifier fromImage:[OCMArg isNil] withIdentifier:[OCMArg isNil]]);
- OCMExpect([mockDelegate multiplexImageNode:imageNode didFinishDownloadingImageWithIdentifier:imageIdentifier error:[OCMArg isNil]]);
-
- imageNode.imageIdentifiers = @[imageIdentifier];
- // Kick off loading.
- [imageNode reloadImageIdentifierSources];
-
- // Wait until the image is loaded.
- [self expectationForPredicate:[NSPredicate predicateWithFormat:@"loadedImageIdentifier = %@", imageIdentifier] evaluatedWithObject:imageNode handler:nil];
- [self waitForExpectationsWithTimeout:30 handler:nil];
-}
-
-- (void)testThatSettingAnImageExternallyWillThrow
-{
- XCTAssertThrows(imageNode.image = [UIImage imageNamed:@""]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASMutableAttributedStringBuilderTests.mm b/submodules/AsyncDisplayKit/Tests/ASMutableAttributedStringBuilderTests.mm
deleted file mode 100644
index 2415dfc626..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASMutableAttributedStringBuilderTests.mm
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// ASMutableAttributedStringBuilderTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-
-@interface ASMutableAttributedStringBuilderTests : XCTestCase
-
-@end
-
-@implementation ASMutableAttributedStringBuilderTests
-
-- (NSString *)_string
-{
- return @"Normcore PBR hella, viral slow-carb mustache chillwave church-key cornhole messenger bag swag vinyl biodiesel ethnic. Fashion axe messenger bag raw denim street art. Flannel Wes Anderson normcore church-key 8-bit. Master cleanse four loko try-hard Carles stumptown ennui, twee literally wayfarers kitsch tofu PBR. Cliche organic post-ironic Wes Anderson kale chips fashion axe. Narwhal Blue Bottle sustainable, Odd Future Godard sriracha banjo disrupt Marfa irony pug Wes Anderson YOLO yr church-key. Mlkshk Intelligentsia semiotics quinoa, butcher meggings wolf Bushwick keffiyeh ethnic pour-over Pinterest letterpress.";
-}
-
-- (ASMutableAttributedStringBuilder *)_builder
-{
- return [[ASMutableAttributedStringBuilder alloc] initWithString:[self _string]];
-}
-
-- (NSRange)_randomizedRangeForStringBuilder:(ASMutableAttributedStringBuilder *)builder
-{
- NSUInteger loc = arc4random() % (builder.length - 1);
- NSUInteger len = arc4random() % (builder.length - loc);
- len = ((len > 0) ? len : 1);
- return NSMakeRange(loc, len);
-}
-
-- (void)testSimpleAttributions
-{
- // Add a attributes, and verify that they get set on the correct locations.
- for (int i = 0; i < 100; i++) {
- ASMutableAttributedStringBuilder *builder = [self _builder];
- NSRange range = [self _randomizedRangeForStringBuilder:builder];
- NSString *keyValue = [NSString stringWithFormat:@"%d", i];
- [builder addAttribute:keyValue value:keyValue range:range];
- NSAttributedString *attrStr = [builder composedAttributedString];
- XCTAssertEqual(builder.length, attrStr.length, @"out string should have same length as builder");
- __block BOOL found = NO;
- [attrStr enumerateAttributesInRange:NSMakeRange(0, attrStr.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange r, BOOL *stop) {
- if ([attrs[keyValue] isEqualToString:keyValue]) {
- XCTAssertTrue(NSEqualRanges(range, r), @"enumerated range %@ should be equal to the set range %@", NSStringFromRange(r), NSStringFromRange(range));
- found = YES;
- }
- }];
- XCTAssertTrue(found, @"enumeration should have found the attribute we set");
- }
-}
-
-- (void)testSetOverAdd
-{
- ASMutableAttributedStringBuilder *builder = [self _builder];
- NSRange addRange = NSMakeRange(0, builder.length);
- NSRange setRange = NSMakeRange(0, 1);
- [builder addAttribute:@"attr" value:@"val1" range:addRange];
- [builder setAttributes:@{@"attr" : @"val2"} range:setRange];
- NSAttributedString *attrStr = [builder composedAttributedString];
- NSRange setRangeOut;
- NSString *setAttr = [attrStr attribute:@"attr" atIndex:0 effectiveRange:&setRangeOut];
- XCTAssertTrue(NSEqualRanges(setRange, setRangeOut), @"The out set range should equal the range we used originally");
- XCTAssertEqualObjects(setAttr, @"val2", @"the set value should be val2");
-
- NSRange addRangeOut;
- NSString *addAttr = [attrStr attribute:@"attr" atIndex:2 effectiveRange:&addRangeOut];
- XCTAssertTrue(NSEqualRanges(NSMakeRange(1, builder.length - 1), addRangeOut), @"the add range should only cover beyond the set range");
- XCTAssertEqualObjects(addAttr, @"val1", @"the added attribute should be present at index 2");
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASNavigationControllerTests.mm b/submodules/AsyncDisplayKit/Tests/ASNavigationControllerTests.mm
deleted file mode 100644
index d9ed2464c0..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASNavigationControllerTests.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// ASNavigationControllerTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-
-#import
-
-@interface ASNavigationControllerTests : XCTestCase
-@end
-
-@implementation ASNavigationControllerTests
-
-- (void)testSetViewControllers {
- ASViewController *firstController = [ASViewController new];
- ASViewController *secondController = [ASViewController new];
- NSArray *expectedViewControllerStack = @[firstController, secondController];
- ASNavigationController *navigationController = [ASNavigationController new];
- [navigationController setViewControllers:@[firstController, secondController]];
- XCTAssertEqual(navigationController.topViewController, secondController);
- XCTAssertEqual(navigationController.visibleViewController, secondController);
- XCTAssertTrue([navigationController.viewControllers isEqualToArray:expectedViewControllerStack]);
-}
-
-- (void)testPopViewController {
- ASViewController *firstController = [ASViewController new];
- ASViewController *secondController = [ASViewController new];
- NSArray *expectedViewControllerStack = @[firstController];
- ASNavigationController *navigationController = [ASNavigationController new];
- [navigationController setViewControllers:@[firstController, secondController]];
- [navigationController popViewControllerAnimated:false];
- XCTAssertEqual(navigationController.topViewController, firstController);
- XCTAssertEqual(navigationController.visibleViewController, firstController);
- XCTAssertTrue([navigationController.viewControllers isEqualToArray:expectedViewControllerStack]);
-}
-
-- (void)testPushViewController {
- ASViewController *firstController = [ASViewController new];
- ASViewController *secondController = [ASViewController new];
- NSArray *expectedViewControllerStack = @[firstController, secondController];
- ASNavigationController *navigationController = [[ASNavigationController new] initWithRootViewController:firstController];
- [navigationController pushViewController:secondController animated:false];
- XCTAssertEqual(navigationController.topViewController, secondController);
- XCTAssertEqual(navigationController.visibleViewController, secondController);
- XCTAssertTrue([navigationController.viewControllers isEqualToArray:expectedViewControllerStack]);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASNetworkImageNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASNetworkImageNodeTests.mm
deleted file mode 100644
index f794ba9e7f..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASNetworkImageNodeTests.mm
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// ASNetworkImageNodeTests.mm
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-#import
-
-@interface ASNetworkImageNodeTests : XCTestCase
-
-@end
-
-@interface ASTestImageDownloader : NSObject
-@end
-@interface ASTestImageCache : NSObject
-@end
-
-@implementation ASNetworkImageNodeTests {
- ASNetworkImageNode *node;
- id downloader;
- id cache;
-}
-
-- (void)setUp
-{
- [super setUp];
- cache = [OCMockObject partialMockForObject:[[ASTestImageCache alloc] init]];
- downloader = [OCMockObject partialMockForObject:[[ASTestImageDownloader alloc] init]];
- node = [[ASNetworkImageNode alloc] initWithCache:cache downloader:downloader];
-}
-
-/// Test is flaky: https://github.com/facebook/AsyncDisplayKit/issues/2898
-- (void)DISABLED_testThatProgressBlockIsSetAndClearedCorrectlyOnVisibility
-{
- node.URL = [NSURL URLWithString:@"http://imageA"];
-
- // Enter preload range, wait for download start.
- [[[downloader expect] andForwardToRealObject] downloadImageWithURL:[OCMArg isNotNil] callbackQueue:OCMOCK_ANY downloadProgress:OCMOCK_ANY completion:OCMOCK_ANY];
- [node enterInterfaceState:ASInterfaceStatePreload];
- [downloader verifyWithDelay:5];
-
- // Make the node visible.
- [[downloader expect] setProgressImageBlock:[OCMArg isNotNil] callbackQueue:OCMOCK_ANY withDownloadIdentifier:@0];
- [node enterInterfaceState:ASInterfaceStateInHierarchy];
- [downloader verify];
-
- // Make the node invisible.
- [[downloader expect] setProgressImageBlock:[OCMArg isNil] callbackQueue:OCMOCK_ANY withDownloadIdentifier:@0];
- [node exitInterfaceState:ASInterfaceStateInHierarchy];
- [downloader verify];
-}
-
-- (void)testThatProgressBlockIsSetAndClearedCorrectlyOnChangeURL
-{
- [node layer];
- [node enterInterfaceState:ASInterfaceStateInHierarchy];
-
- // Set URL while visible, should set progress block
- [[downloader expect] setProgressImageBlock:[OCMArg isNotNil] callbackQueue:OCMOCK_ANY withDownloadIdentifier:@0];
- node.URL = [NSURL URLWithString:@"http://imageA"];
- [downloader verifyWithDelay:5];
-
- // Change URL while visible, should clear prior block and set new one
- [[downloader expect] setProgressImageBlock:[OCMArg isNil] callbackQueue:OCMOCK_ANY withDownloadIdentifier:@0];
- [[downloader expect] cancelImageDownloadForIdentifier:@0];
- [[downloader expect] setProgressImageBlock:[OCMArg isNotNil] callbackQueue:OCMOCK_ANY withDownloadIdentifier:@1];
- node.URL = [NSURL URLWithString:@"http://imageB"];
- [downloader verifyWithDelay:5];
-}
-
-- (void)testThatSettingAnImageWillStayForEnteringAndExitingPreloadState
-{
- UIImage *image = [[UIImage alloc] init];
- ASNetworkImageNode *networkImageNode = [[ASNetworkImageNode alloc] init];
- networkImageNode.image = image;
- [networkImageNode enterHierarchyState:ASHierarchyStateRangeManaged]; // Ensures didExitPreloadState is called
- XCTAssertEqualObjects(image, networkImageNode.image);
- [networkImageNode enterInterfaceState:ASInterfaceStatePreload];
- XCTAssertEqualObjects(image, networkImageNode.image);
- [networkImageNode exitInterfaceState:ASInterfaceStatePreload];
- XCTAssertEqualObjects(image, networkImageNode.image);
- [networkImageNode exitHierarchyState:ASHierarchyStateRangeManaged];
- XCTAssertEqualObjects(image, networkImageNode.image);
-}
-
-- (void)testThatSettingADefaultImageWillStayForEnteringAndExitingPreloadState
-{
- UIImage *image = [[UIImage alloc] init];
- ASNetworkImageNode *networkImageNode = [[ASNetworkImageNode alloc] init];
- networkImageNode.defaultImage = image;
- [networkImageNode enterHierarchyState:ASHierarchyStateRangeManaged]; // Ensures didExitPreloadState is called
- XCTAssertEqualObjects(image, networkImageNode.defaultImage);
- [networkImageNode enterInterfaceState:ASInterfaceStatePreload];
- XCTAssertEqualObjects(image, networkImageNode.defaultImage);
- [networkImageNode exitInterfaceState:ASInterfaceStatePreload];
- XCTAssertEqualObjects(image, networkImageNode.defaultImage);
- [networkImageNode exitHierarchyState:ASHierarchyStateRangeManaged];
- XCTAssertEqualObjects(image, networkImageNode.defaultImage);
-}
-
-@end
-
-@implementation ASTestImageCache
-
-- (void)cachedImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue completion:(ASImageCacherCompletion)completion
-{
- completion(nil);
-}
-
-@end
-
-@implementation ASTestImageDownloader {
- NSInteger _currentDownloadID;
-}
-
-- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier
-{
- // nop
-}
-
-- (id)downloadImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue downloadProgress:(ASImageDownloaderProgress)downloadProgress completion:(ASImageDownloaderCompletion)completion
-{
- return @(_currentDownloadID++);
-}
-
-- (void)setProgressImageBlock:(ASImageDownloaderProgressImage)progressBlock callbackQueue:(dispatch_queue_t)callbackQueue withDownloadIdentifier:(id)downloadIdentifier
-{
- // nop
-}
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASOverlayLayoutSpecSnapshotTests.mm b/submodules/AsyncDisplayKit/Tests/ASOverlayLayoutSpecSnapshotTests.mm
deleted file mode 100644
index a50baa9ef4..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASOverlayLayoutSpecSnapshotTests.mm
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// ASOverlayLayoutSpecSnapshotTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASLayoutSpecSnapshotTestsHelper.h"
-
-#import
-#import
-
-static const ASSizeRange kSize = {{320, 320}, {320, 320}};
-
-@interface ASOverlayLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
-@end
-
-@implementation ASOverlayLayoutSpecSnapshotTests
-
-- (void)testOverlay
-{
- ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
- ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blackColor], {20, 20});
-
- ASLayoutSpec *layoutSpec =
- [ASOverlayLayoutSpec
- overlayLayoutSpecWithChild:backgroundNode
- overlay:
- [ASCenterLayoutSpec
- centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY
- sizingOptions:{}
- child:foregroundNode]];
-
- [self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier: nil];
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASPagerNodeTests.mm b/submodules/AsyncDisplayKit/Tests/ASPagerNodeTests.mm
deleted file mode 100644
index 416efaae3d..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASPagerNodeTests.mm
+++ /dev/null
@@ -1,179 +0,0 @@
-//
-// ASPagerNodeTests.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-
-@interface ASPagerNodeTestDataSource : NSObject
-@end
-
-@implementation ASPagerNodeTestDataSource
-
-- (instancetype)init
-{
- if (!(self = [super init])) {
- return nil;
- }
- return self;
-}
-
-- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode
-{
- return 2;
-}
-
-- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
-{
- return [[ASCellNode alloc] init];
-}
-
-@end
-
-@interface ASPagerNodeTestController: UIViewController
-@property (nonatomic) ASPagerNodeTestDataSource *testDataSource;
-@property (nonatomic) ASPagerNode *pagerNode;
-@end
-
-@implementation ASPagerNodeTestController
-
-- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Populate these immediately so that they're not unexpectedly nil during tests.
- self.testDataSource = [[ASPagerNodeTestDataSource alloc] init];
-
- self.pagerNode = [[ASPagerNode alloc] init];
- self.pagerNode.dataSource = self.testDataSource;
-
- [self.view addSubnode:self.pagerNode];
- }
- return self;
-}
-
-@end
-
-@interface ASPagerNodeTests : XCTestCase
-@property (nonatomic) ASPagerNode *pagerNode;
-
-@property (nonatomic) ASPagerNodeTestDataSource *testDataSource;
-@end
-
-@implementation ASPagerNodeTests
-
-- (void)testPagerReturnsIndexOfPages
-{
- ASPagerNodeTestController *testController = [self testController];
-
- ASCellNode *cellNode = [testController.pagerNode nodeForPageAtIndex:0];
-
- XCTAssertEqual([testController.pagerNode indexOfPageWithNode:cellNode], 0);
-}
-
-- (void)testPagerReturnsNotFoundForCellThatDontExistInPager
-{
- ASPagerNodeTestController *testController = [self testController];
-
- ASCellNode *badNode = [[ASCellNode alloc] init];
-
- XCTAssertEqual([testController.pagerNode indexOfPageWithNode:badNode], NSNotFound);
-}
-
-- (void)testScrollPageToIndex
-{
- ASPagerNodeTestController *testController = [self testController];
- testController.pagerNode.frame = CGRectMake(0, 0, 500, 500);
- [testController.pagerNode scrollToPageAtIndex:1 animated:false];
-
- XCTAssertEqual(testController.pagerNode.currentPageIndex, 1);
-}
-
-- (ASPagerNodeTestController *)testController
-{
- ASPagerNodeTestController *testController = [[ASPagerNodeTestController alloc] initWithNibName:nil bundle:nil];
- UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- [window makeKeyAndVisible];
- window.rootViewController = testController;
-
- [testController.pagerNode reloadData];
- [testController.pagerNode setNeedsLayout];
-
- return testController;
-}
-
-// Disabled due to flakiness https://github.com/facebook/AsyncDisplayKit/issues/2818
-- (void)DISABLED_testThatRootPagerNodeDoesGetTheRightInsetWhilePoppingBack
-{
- UICollectionViewCell *cell = nil;
-
- UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- ASDisplayNode *node = [[ASDisplayNode alloc] init];
- node.automaticallyManagesSubnodes = YES;
-
- ASPagerNodeTestDataSource *dataSource = [[ASPagerNodeTestDataSource alloc] init];
- ASPagerNode *pagerNode = [[ASPagerNode alloc] init];
- pagerNode.dataSource = dataSource;
- node.layoutSpecBlock = ^(ASDisplayNode *node, ASSizeRange constrainedSize){
- return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:pagerNode];
- };
- ASViewController *vc = [[ASViewController alloc] initWithNode:node];
- UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
- window.rootViewController = nav;
- [window makeKeyAndVisible];
- [window layoutIfNeeded];
-
- // Wait until view controller is visible
- XCTestExpectation *e = [self expectationWithDescription:@"Transition completed"];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- [e fulfill];
- });
- [self waitForExpectationsWithTimeout:2 handler:nil];
-
- // Test initial values
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- cell = [pagerNode.view cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
-#pragma clang diagnostic pop
- XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(node.frame));
- XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(cell.frame));
- XCTAssertEqual(pagerNode.contentOffset.y, 0);
- XCTAssertEqual(pagerNode.contentInset.top, 0);
-
- e = [self expectationWithDescription:@"Transition completed"];
- // Push another view controller
- UIViewController *vc2 = [[UIViewController alloc] init];
- vc2.view.frame = nav.view.bounds;
- vc2.view.backgroundColor = [UIColor blueColor];
- [nav pushViewController:vc2 animated:YES];
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.505 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- [e fulfill];
- });
- [self waitForExpectationsWithTimeout:2 handler:nil];
-
- // Pop view controller
- e = [self expectationWithDescription:@"Transition completed"];
- [vc2.navigationController popViewControllerAnimated:YES];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.505 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- [e fulfill];
- });
- [self waitForExpectationsWithTimeout:2 handler:nil];
-
- // Test values again after popping the view controller
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- cell = [pagerNode.view cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
-#pragma clang diagnostic pop
- XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(node.frame));
- XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(cell.frame));
- XCTAssertEqual(pagerNode.contentOffset.y, 0);
- XCTAssertEqual(pagerNode.contentInset.top, 0);
-}
-
-@end
diff --git a/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.h b/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.h
deleted file mode 100644
index 49196d451c..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// ASPerformanceTestContext.h
-// Texture
-//
-// Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import
-#import
-#import
-
-#define ASXCTAssertRelativePerformanceInRange(test, caseName, min, max) \
- _XCTPrimitiveAssertLessThanOrEqual(self, test.results[caseName].relativePerformance, @#caseName, max, @#max);\
- _XCTPrimitiveAssertGreaterThanOrEqual(self, test.results[caseName].relativePerformance, @#caseName, min, @#min)
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef void (^ASTestPerformanceCaseBlock)(NSUInteger i, dispatch_block_t startMeasuring, dispatch_block_t stopMeasuring);
-
-@interface ASPerformanceTestResult : NSObject
-@property (nonatomic, readonly) NSTimeInterval timePer1000;
-@property (nonatomic, readonly) NSString *caseName;
-
-@property (nonatomic, readonly, getter=isReferenceCase) BOOL referenceCase;
-@property (nonatomic, readonly) float relativePerformance;
-
-@property (nonatomic, readonly) NSMutableDictionary *userInfo;
-@end
-
-@interface ASPerformanceTestContext : NSObject
-
-/**
- * The first case you add here will be considered the reference case.
- */
-- (void)addCaseWithName:(NSString *)caseName block:(AS_NOESCAPE ASTestPerformanceCaseBlock)block;
-
-@property (nonatomic, copy, readonly) NSDictionary *results;
-
-- (BOOL)areAllUserInfosEqual;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.mm b/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.mm
deleted file mode 100644
index 15c6787596..0000000000
--- a/submodules/AsyncDisplayKit/Tests/ASPerformanceTestContext.mm
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// ASPerformanceTestContext.mm
-// Texture
-//
-// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
-// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
-// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
-//
-
-#import "ASPerformanceTestContext.h"
-
-#import