/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FacebookShare
import UIKit

extension ShareViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        guard
            let appID = Bundle.main.object(forInfoDictionaryKey: "FacebookAppID") as? String,
            appID != "{your-app-id}"
        else {
            return presentAlert(
                title: "Invalid App Identifier",
                message: "Please enter your Facebook application identifier in your Info.plist. This can be found on the developer portal at developers.facebook.com"
            )
        }

        guard
            let urlTypes = Bundle.main.object(forInfoDictionaryKey: "CFBundleURLTypes") as? [[String: [String]]],
            let scheme = urlTypes.first?["CFBundleURLSchemes"]?.first,
            scheme != "fb{your-app-id}"
        else {
            return presentAlert(
                title: "Invalid URL Scheme",
                message: "Please update the url scheme in your Info.plist with your Facebook application identifier to allow for the login flow to reopen this app"
            )
        }
    }

    func presentAlert(title: String, message: String) {
        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let dismissAction = UIAlertAction(title: "Dismiss", style: .default)
        alertController.addAction(dismissAction)

        present(alertController, animated: true)
    }

    func presentAlert(for error: Error) {
        let nsError = error as NSError

        guard let sdkMessage = nsError.userInfo["com.facebook.sdk:FBSDKErrorDeveloperMessageKey"] as? String
        else {
            preconditionFailure("Errors from the SDK should have a developer facing message")
        }

        presentAlert(title: "Sharing Error", message: sdkMessage)
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

final class RPSAutoAppLinkSwiftViewController: UIViewController {
    var product: Coffee?
    var data: Dictionary<String, Any>?

    let paddingLen: CGFloat = 10
    let frameHeight: CGFloat = 30

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = .white
        let scrolllView: UIScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
        let frameWidth = scrolllView.frame.size.width - paddingLen*2

        let nameLabel: UILabel = UILabel(frame: CGRect(x: paddingLen, y: 50, width: frameWidth, height: frameHeight))
        nameLabel.font = UIFont.boldSystemFont(ofSize: 24)
        nameLabel.textColor = .gray

        let descLabel:UILabel = UILabel(frame: CGRect(x: paddingLen, y: 90, width: frameWidth, height: frameHeight + 10))
        descLabel.font = UIFont.systemFont(ofSize: 14)
        descLabel.textColor = .lightGray
        descLabel.numberOfLines = 0

        let priceLabel:UILabel = UILabel(frame: CGRect(x: paddingLen, y: 140, width: frameWidth, height: frameHeight - 10))
        priceLabel.font = UIFont.systemFont(ofSize: 20)
        priceLabel.textColor = .lightGray

        if self.product == nil {
            self.product = Coffee(name: "SWIFT Coffee", desc: "I am just a SWIFT coffee", price: 1)
        }
        nameLabel.text = self.product!.name
        descLabel.text = "Description: " + self.product!.desc
        priceLabel.text = "Price: $" + self.product!.price.description

        scrolllView.addSubview(nameLabel)
        scrolllView.addSubview(descLabel)
        scrolllView.addSubview(priceLabel)

        if let data = self.data {
            let dataLabel: UILabel = UILabel()
            dataLabel.font = UIFont.systemFont(ofSize: 20)
            dataLabel.textColor = .blue
            dataLabel.text = String.init(format: "data is: %@", data)
            dataLabel.numberOfLines = 0
            let size: CGSize = (dataLabel.text! as NSString).boundingRect(with: CGSize(width: frameWidth, height: 1000), options: .usesLineFragmentOrigin, attributes: [.font: dataLabel.font!], context: nil).size
            dataLabel.frame = CGRect(x: paddingLen, y: 190, width: size.width, height: size.height)
            scrolllView.addSubview(dataLabel)
        }
        self.view.addSubview(scrolllView)
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FacebookAEM

struct VerifyFacebookAEM {
    func verifySymbols() {
      _ = AEMReporter()
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FacebookCore

struct VerifyFacebookCore {
    func verifySymbols() {
        // Verifies Swift only symbol
        _ = Permission.email

        // Verifies ObjC symbol
        Settings.appID = "Foo"

        // Additional Sanity Check
        AppEvents.logEvent(AppEvents.Name("foo"))
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FacebookLogin

struct VerifyFacebookLogin {
    func verifyTransitiveSymbols() {
        // Verifies Swift only symbol
        _ = Permission.email

        // Verifies ObjC symbol
        Settings.appID = "Foo"

        // Additional Sanity Check
        AppEvents.logEvent(AppEvents.Name("foo"))
    }

    func verifyLoginSymbols() {
        // Verifies Swift only symbol
        _ = LoginResult.cancelled

        // Verifies Swift only initializer
        _ = LoginManager(defaultAudience: .everyone)

        // Verifies ObjC initializer
        _ = LoginManager()
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FacebookShare

struct VerifyFacebookShare {
    func verifyTransitiveSymbols() {
        // Verifies Swift only symbol
        _ = Permission.email

        // Verifies ObjC symbol
        Settings.appID = "Foo"

        // Additional Sanity Check
        AppEvents.logEvent(AppEvents.Name("foo"))
    }

    func verifyShareSymbols() {
        // Verifies ObjC symbol
        _ = ShareDialog()

        // Verifies Swift only symbol
        _ = ShareDialog.Mode.automatic.description
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

#if canImport(FBAEMKit)
@_exported import FBAEMKit
#endif


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

// Need to treat ObjC as separate dependency for SPM because it does not
// support mixed Swift and ObjC sources. In order to expose the dependent
// interface we need to pass through the import of the `FBSDKShareKitObjC`
// target defined in Package.swift.
// See: https://forums.swift.org/t/16648/2 for more details
//

#if canImport(FBSDKCoreKit)
@_exported import FBSDKCoreKit
#endif


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Accelerate


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

#if canImport(FBSDKGamingServicesKit)
@_exported import FBSDKGamingServicesKit
#endif


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

#if canImport(FBSDKLoginKit)
@_exported import FBSDKLoginKit
#endif


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

#if canImport(FBSDKShareKit)
@_exported import FBSDKShareKit
#endif


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

import FBSDKCoreKit
import FBSDKGamingServicesKit
import FBSDKLoginKit
import FBSDKShareKit

@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit
import FacebookCore

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        ApplicationDelegate.shared.application(
            application,
            didFinishLaunchingWithOptions: launchOptions
        )
        return true
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }

}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

final class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

private struct DecodingError: Error {}

public enum CodabilityTesting {
  public static func encodeAndDecode<T: NSCoding & NSObject>(_ object: T) throws -> T {
    let encodedData = try NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false)
    guard let decodedObject = try NSKeyedUnarchiver.unarchivedObject(ofClass: T.self, from: encodedData) else {
      throw DecodingError()
    }
    return decodedObject
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
public final class Fuzzer: NSObject {

  private static let values: [Any] = [
    // Booleans
    true,
    false,
    // Numbers
    1,
    0,
    -1,
    Int.max,
    Double.greatestFiniteMagnitude,
    Float.greatestFiniteMagnitude,
    Double.leastNonzeroMagnitude,
    Double.leastNormalMagnitude,
    // Strings
    "1",
    "a",
    " ",
    "{}",
    "[]",
    "{",
    "}",
    "[ { \"something\": nonexistent } ]",
    "\\{ \"foo\": \"bar\" \\}",
    // Data
    Data(),
    "Foo".data(using: .utf8) ?? Data(),
    Data(count: 100),

    // swiftlint:disable:next force_try
    try! JSONSerialization.data(withJSONObject: ["foo": "bar"], options: .fragmentsAllowed),
    // swiftlint:enable force_try
    // Special Characters
    "\\",
    // Arrays
    [],
    [1, 2, 3],
    [1, 2, 3, "a", "b", "c"],
    0 ... 100,
    "a" ..< "z",
    // Dictionaries
    "[:]",
    [:],
    ["Foo": "Bar"],
    ["": [1, 2, 3]],
    ["Foo": true],
    ["Foo": ["Bar": "Baz"]],
    ["Foo": ["a", 1, [:]]],
  ]

  public class var random: AnyObject {
    values.randomElement() as AnyObject
  }

  /// Randomizes the values of a JSON object
  /// Will not replace keys. Will either change their values or trim them entirely.
  /// Will be called recursively on dictionaries and arrays
  public class func randomize(json: Any) -> Any {
    if var dictionary = json as? [String: Any] {
      return randomizeInPlace(json: &dictionary)
    } else if var array = json as? [Any] {
      return randomizeInPlace(array: &array)
    } else {
      return json
    }
  }

  private class func randomizeInPlace(array: inout [Any]) -> [Any] {
    var array = array

    array.enumerated().forEach { enumeration in
      if var dictionary = enumeration.element as? [String: Any] {
        array[enumeration.offset] = Bool.random() ? dictionary : randomizeInPlace(json: &dictionary)
      } else if let subarray = enumeration.element as? [Any] {
        array[enumeration.offset] = Bool.random() ? subarray : randomizeInPlace(array: &array)
      } else {
        array[enumeration.offset] = Bool.random() ? enumeration.element : random
      }
    }

    return array
  }

  private class func randomizeInPlace(json: inout [String: Any]) -> [String: Any] {
    json.keys.forEach { key in
      if var value = json[key] as? [String: Any] {
        json[key] = Bool.random() ? random : randomizeInPlace(json: &value)
      }
      // randomize array values if they are dictionaries
      else if var values = json[key] as? [Any] {
        json[key] = Bool.random() ? values : randomizeInPlace(array: &values)
      } else {
        if Bool.random() {
          json[key] = random
        } else if Bool.random() {
          json.removeValue(forKey: key)
        }
      }
    }

    return json
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class SampleAccessTokens: NSObject {

  public static let defaultTokenString = "token123"
  public static let defaultAppID = "appID123"
  public static let defaultUserID = "user123"

  public static var validToken = AccessToken(
    tokenString: defaultTokenString,
    permissions: [],
    declinedPermissions: [],
    expiredPermissions: [],
    appID: defaultAppID,
    userID: defaultUserID,
    expirationDate: nil,
    refreshDate: nil,
    dataAccessExpirationDate: nil
  )

  public static var expiredToken = AccessToken(
    tokenString: defaultTokenString,
    permissions: [],
    declinedPermissions: [],
    expiredPermissions: [],
    appID: defaultAppID,
    userID: defaultUserID,
    expirationDate: .distantPast,
    refreshDate: nil,
    dataAccessExpirationDate: nil
  )

  public static func create(withRefreshDate date: Date?) -> AccessToken {
    AccessToken(
      tokenString: defaultTokenString,
      permissions: [],
      declinedPermissions: [],
      expiredPermissions: [],
      appID: defaultAppID,
      userID: defaultUserID,
      expirationDate: nil,
      refreshDate: date,
      dataAccessExpirationDate: nil
    )
  }

  public static func create(dataAccessExpirationDate date: Date) -> AccessToken {
    AccessToken(
      tokenString: defaultTokenString,
      permissions: [],
      declinedPermissions: [],
      expiredPermissions: [],
      appID: defaultAppID,
      userID: defaultUserID,
      expirationDate: nil,
      refreshDate: nil,
      dataAccessExpirationDate: date
    )
  }

  public static func create(withPermissions permissions: [String]) -> AccessToken {
    AccessToken(
      tokenString: defaultTokenString,
      permissions: permissions,
      declinedPermissions: [],
      expiredPermissions: [],
      appID: defaultAppID,
      userID: defaultUserID,
      expirationDate: nil,
      refreshDate: nil,
      dataAccessExpirationDate: nil
    )
  }

  public static func create(
    withPermissions permissions: [String],
    declinedPermissions: [String] = [],
    expiredPermissions: [String] = []
  ) -> AccessToken {
    AccessToken(
      tokenString: defaultTokenString,
      permissions: permissions,
      declinedPermissions: declinedPermissions,
      expiredPermissions: expiredPermissions,
      appID: defaultAppID,
      userID: defaultUserID,
      expirationDate: nil,
      refreshDate: nil,
      dataAccessExpirationDate: nil
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class SampleAuthenticationToken: NSObject {

  public static var validToken: AuthenticationToken {
    AuthenticationToken(
      tokenString: "fakeTokenString",
      nonce: "fakeNonce"
    )
  }

  public static func validToken(withGraphDomain domain: String) -> AuthenticationToken {
    AuthenticationToken(
      tokenString: "fakeTokenString",
      nonce: "fakeNonce",
      graphDomain: domain
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

public struct SampleError: Error, Equatable {
  private let uuid = UUID()

  public init() {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

public enum SampleURLs {
  // swiftlint:disable force_unwrapping
  public static let valid = URL(string: "https://www.example.com")!
  public static let validApp = URL(string: "fb://test.com")!
  public static let validUniversalLink = URL(string: "https://www.test.com")!
  public static let validPNG = URL(string: "https://www.example.com/babyamnimal.png")!
  // swiftlint:enable force_unwrapping

  public static func valid(path: String) -> URL {
    valid.appendingPathComponent(path)
  }

  public static func valid(queryItems: [URLQueryItem]) -> URL {
    // swiftlint:disable:next force_unwrapping
    var components = URLComponents(url: valid, resolvingAgainstBaseURL: false)!
    components.queryItems = queryItems
    return components.url! // swiftlint:disable:this force_unwrapping
  }
}

public enum SampleURLRequest {
  public static let valid = URLRequest(url: SampleURLs.valid)
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class SampleUserProfiles: NSObject {

  public static let defaultName = "John Smith"
  public static let defaultImageURL = URL(string: "http://www.example.com/image.jpg")
  public static let defaultUserID = "123"

  public static var missingImageURL = createValid(imageURL: nil)
  public static var validLimited = createValid(isLimited: true)

  public static func createValid(userID: String) -> Profile {
    createValid(userID: userID, name: defaultName)
  }

  public static func createValid(isExpired: Bool) -> Profile {
    createValid(name: defaultName, isExpired: isExpired)
  }

  public static func createValid(
    userID: String = defaultUserID,
    name: String? = defaultName,
    imageURL url: URL? = defaultImageURL,
    isExpired: Bool = false,
    isLimited: Bool = false
  ) -> Profile {
    Profile(
      userID: userID,
      firstName: "John",
      middleName: "K",
      lastName: "Smith",
      name: name,
      linkURL: URL(string: "http://www.example.com"),
      refreshDate: isExpired ? .distantPast : .distantFuture,
      imageURL: url,
      email: "example@example.com",
      friendIDs: [
        "456",
        "789",
      ],
      birthday: Date(timeIntervalSince1970: 0),
      ageRange: UserAgeRange(from: ["min": 21]),
      hometown: Location(from: ["id": "112724962075996", "name": "Martinez, California"]),
      location: Location(from: ["id": "110843418940484", "name": "Seattle, Washington"]),
      gender: "male",
      isLimited: isLimited
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

public final class TestAccessTokenProvider: _AccessTokenProviding {

  public static var stubbedAccessToken: AccessToken?
  public static var tokenCache: TokenCaching?
  public static var current: AccessToken? {
    get { stubbedAccessToken }
    set {} // swiftlint:disable:this unused_setter_value
  }

  public init() {}

  public static func reset() {
    tokenCache = nil
    stubbedAccessToken = nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestAccessTokenWallet: NSObject, _AccessTokenProviding, _TokenStringProviding {

  public static var tokenCache: TokenCaching?
  public static var stubbedCurrentAccessToken: AccessToken?
  public static var wasTokenRead = false

  public static var current: AccessToken? {
    get {
      wasTokenRead = true
      return stubbedCurrentAccessToken
    }
    set {
      stubbedCurrentAccessToken = newValue
    }
  }

  public static var tokenString: String? {
    current?.tokenString
  }

  public static func reset() {
    tokenCache = nil
    current = nil
    wasTokenRead = false
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBAEMKit
import Foundation

public final class TestAEMNetworker: NSObject, AEMNetworking {

  public var capturedGraphPath: String?
  public var capturedParameters = [String: Any]()
  public var capturedTokenString: String?
  public var capturedHttpMethod: String?
  public var capturedCompletionHandler: FBGraphRequestCompletion?
  public var startCallCount = 0

  public func startGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any],
    tokenString: String?,
    httpMethod method: String?,
    completion: @escaping FBGraphRequestCompletion
  ) {
    capturedGraphPath = graphPath
    capturedParameters = parameters
    capturedTokenString = tokenString
    capturedHttpMethod = method
    capturedCompletionHandler = completion
    startCallCount += 1
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestAuthenticationTokenWallet: NSObject, _AuthenticationTokenProviding {
  public static var tokenCache: TokenCaching?
  public static var current: AuthenticationToken?

  public static func reset() {
    tokenCache = nil
    current = nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestBridgeAPIRequest: NSObject, BridgeAPIRequestProtocol {
  public var actionID = "1"
  public var methodName: String?
  public var protocolType: FBSDKBridgeAPIProtocolType
  public var `protocol`: BridgeAPIProtocol?
  public var scheme: String

  public let url: URL?

  public init(
    url: URL? = nil,
    protocolType: FBSDKBridgeAPIProtocolType = .native,
    scheme: String = "1"
  ) {
    self.url = url
    self.protocolType = protocolType
    self.scheme = scheme
  }

  public func copy(with zone: NSZone? = nil) -> Any {
    self
  }

  public func requestURL() throws -> URL {
    guard let url = url else {
      throw FakeBridgeAPIRequestError(domain: "tests", code: 0, userInfo: [:])
    }
    return url
  }

  public static func request(withURL url: URL?) -> TestBridgeAPIRequest {
    TestBridgeAPIRequest(url: url)
  }

  public static func request(withURL url: URL, scheme: String) -> TestBridgeAPIRequest {
    TestBridgeAPIRequest(url: url, scheme: scheme)
  }
}

@objc
public final class FakeBridgeAPIRequestError: NSError {}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestBridgeAPIRequestOpener: NSObject, BridgeAPIRequestOpening {

  public var capturedURL: URL?
  public var capturedHandler: SuccessBlock?
  public var capturedRequest: BridgeAPIRequestProtocol?
  public var capturedUseSafariViewController: Bool? // swiftlint:disable:this discouraged_optional_boolean
  public var capturedFromViewController: UIViewController?
  public var capturedCompletionBlock: BridgeAPIResponseBlock?
  public var openURLWithSFVCCount = 0

  public func open(
    _ request: BridgeAPIRequestProtocol,
    useSafariViewController: Bool,
    from fromViewController: UIViewController?,
    completionBlock: @escaping BridgeAPIResponseBlock
  ) {
    capturedRequest = request
    capturedUseSafariViewController = useSafariViewController
    capturedFromViewController = fromViewController
    capturedCompletionBlock = completionBlock
  }

  public func openURLWithSafariViewController(
    url: URL,
    sender: URLOpening?,
    from fromViewController: UIViewController?,
    handler: @escaping SuccessBlock
  ) {
    openURLWithSFVCCount += 1
    handler(true, nil)
  }

  public func open(_ url: URL, sender: URLOpening?, handler: @escaping SuccessBlock) {
    capturedURL = url
    capturedHandler = handler
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import FBSDKCoreKit_Basics
import Foundation

@objcMembers
public final class TestBundle: NSObject, InfoDictionaryProviding {
  private var stubbedInfoDictionary: [String: Any]?
  var lastCapturedKey: String?
  public var capturedKeys = [String]()
  public var didAccessInfoDictionary = false

  // swiftlint:disable:next identifier_name
  public var fb_infoDictionary: [String: Any]? {
    get {
      didAccessInfoDictionary = true
      return stubbedInfoDictionary
    }
    set {
      stubbedInfoDictionary = newValue
    }
  }

  public override convenience init() {
    self.init(infoDictionary: [:])
  }

  public init(infoDictionary: [String: Any] = [:]) {
    stubbedInfoDictionary = infoDictionary
  }

  // swiftlint:disable:next identifier_name
  public var fb_bundleIdentifier: String?

  public func fb_object(forInfoDictionaryKey key: String) -> Any? {
    lastCapturedKey = key
    capturedKeys.append(key)
    return fb_infoDictionary?[key] as Any?
  }

  public func reset() {
    capturedKeys = []
    lastCapturedKey = nil
    stubbedInfoDictionary = nil
    didAccessInfoDictionary = false
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestErrorFactory: NSObject, ErrorCreating {
  public var stubbedError: TestSDKError?

  public func error(
    code: Int,
    userInfo: [String: Any]? = nil,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .general,
      code: code,
      userInfo: userInfo,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func error(
    domain: String,
    code: Int,
    userInfo: [String: Any]? = nil,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .general,
      domain: domain,
      code: code,
      userInfo: userInfo,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func invalidArgumentError(
    name: String,
    value: Any?,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .invalidArgument,
      name: name,
      value: value,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func invalidArgumentError(
    domain: String,
    name: String,
    value: Any?,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .invalidArgument,
      domain: domain,
      name: name,
      value: value,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func requiredArgumentError(
    name: String,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .requiredArgument,
      name: name,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func requiredArgumentError(
    domain: String,
    name: String,
    message: String?,
    underlyingError: Error?
  ) -> Error {
    stubbedError ?? TestSDKError(
      type: .requiredArgument,
      domain: domain,
      name: name,
      message: message,
      underlyingError: underlyingError
    )
  }

  public func unknownError(message: String?, userInfo: [String: Any]? = nil) -> Error {
    stubbedError ?? TestSDKError(type: .unknown, userInfo: userInfo, message: message)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

@testable import FBSDKCoreKit

public final class TestGraphRequest: GraphRequestProtocol {
  public var isGraphErrorRecoveryDisabled = false
  public let hasAttachments = false
  public var parameters: [String: Any]
  public let tokenString: String?
  public let graphPath: String
  public let httpMethod: HTTPMethod
  public let version: String
  public let flags: GraphRequestFlags
  public var stubbedConnection = TestGraphRequestConnection()
  public var capturedCompletionHandler: GraphRequestCompletion?
  public var startCallCount = 0
  public var cancelCallCount = 0

  public init(
    graphPath: String = "",
    parameters: [String: Any]? = nil,
    tokenString: String? = nil,
    httpMethod: HTTPMethod? = nil,
    version: String? = nil,
    flags: GraphRequestFlags? = nil
  ) {
    self.graphPath = graphPath
    self.parameters = parameters ?? [:]
    self.tokenString = tokenString
    self.httpMethod = httpMethod ?? .get
    self.version = version ?? ""
    self.flags = flags ?? []
  }

  public func start(completion handler: GraphRequestCompletion? = nil) -> GraphRequestConnecting {
    capturedCompletionHandler = handler
    startCallCount += 1

    return stubbedConnection
  }

  public func cancel() {
    cancelCallCount += 1
  }

  public func formattedDescription() -> String {
    "Test graph request"
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestGraphRequestConnection: NSObject, GraphRequestConnecting {
  public var requests: NSMutableArray {
    NSMutableArray(
      array: graphRequests.compactMap {
        GraphRequestMetadata(
          request: $0.request,
          completionHandler: $0.completion,
          batchParameters: nil
        )
      }
    )
  }

  public typealias Completion = @convention(block) (GraphRequestConnecting, Any?, Error?) -> Void

  public struct Request {
    public let request: GraphRequestProtocol
    public let completion: GraphRequestCompletion
  }

  public var timeout: TimeInterval = 0
  public var delegate: GraphRequestConnectionDelegate? // swiftlint:disable:this weak_delegate
  public var capturedRequest: GraphRequestProtocol?
  public var capturedRequests = [GraphRequestProtocol]()
  public var capturedCompletion: GraphRequestCompletion?
  public var capturedCompletions = [Completion]()
  public var startCallCount = 0
  public var cancelCallCount = 0

  // Enables us to use the internal requests property
  public var graphRequests = [Request]()

  public func add(_ request: GraphRequestProtocol, completion handler: @escaping GraphRequestCompletion) {
    graphRequests.append(
      Request(
        request: request,
        completion: handler
      )
    )
    capturedRequest = request
    capturedRequests.append(request)
    capturedCompletion = handler
    capturedCompletions.append(handler)
  }

  public func start() {
    startCallCount += 1
  }

  public func cancel() {
    cancelCallCount += 1
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestGraphRequestConnectionFactory: NSObject, GraphRequestConnectionFactoryProtocol {
  public var stubbedConnection: GraphRequestConnecting?

  public override init() {}

  public init(stubbedConnection: GraphRequestConnecting) {
    self.stubbedConnection = stubbedConnection
  }

  public static func create(
    withStubbedConnection connection: GraphRequestConnecting
  ) -> TestGraphRequestConnectionFactory {
    TestGraphRequestConnectionFactory(stubbedConnection: connection)
  }

  // MARK: - GraphRequestConnectionFactoryProtocol

  public func createGraphRequestConnection() -> GraphRequestConnecting {
    guard let connection = stubbedConnection else {
      fatalError("Must stub a connection for a test connection factory")
    }
    return connection
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

public final class TestGraphRequestFactory: GraphRequestFactoryProtocol {

  public var stubbedGraphRequest: TestGraphRequest?

  public var capturedGraphPath: String?
  public var capturedParameters: [String: Any]?
  public var capturedTokenString: String?
  public var capturedHTTPMethod: HTTPMethod?
  public var capturedFlags: GraphRequestFlags?
  public var capturedVersion: String?
  public var capturedRequests = [TestGraphRequest]()

  public init() {}

  public func createGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any],
    tokenString: String?,
    httpMethod: HTTPMethod?,
    flags: GraphRequestFlags
  ) -> GraphRequestProtocol {
    makeRequest(
      graphPath: graphPath,
      parameters: parameters,
      tokenString: tokenString,
      httpMethod: httpMethod,
      flags: flags
    )
  }

  public func createGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any],
    httpMethod: HTTPMethod
  ) -> GraphRequestProtocol {
    makeRequest(
      graphPath: graphPath,
      parameters: parameters,
      httpMethod: httpMethod
    )
  }

  public func createGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any],
    tokenString: String?,
    version: String?,
    httpMethod: HTTPMethod
  ) -> GraphRequestProtocol {
    makeRequest(
      graphPath: graphPath,
      parameters: parameters,
      tokenString: tokenString,
      version: version,
      httpMethod: httpMethod
    )
  }

  public func createGraphRequest(withGraphPath graphPath: String) -> GraphRequestProtocol {
    makeRequest(graphPath: graphPath)
  }

  public func createGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any]
  ) -> GraphRequestProtocol {
    makeRequest(graphPath: graphPath, parameters: parameters)
  }

  public func createGraphRequest(
    withGraphPath graphPath: String,
    parameters: [String: Any],
    flags: GraphRequestFlags
  ) -> GraphRequestProtocol {
    makeRequest(graphPath: graphPath, parameters: parameters, flags: flags)
  }

  private func makeRequest(
    graphPath: String,
    parameters: [String: Any]? = nil,
    tokenString: String? = nil,
    version: String? = nil,
    httpMethod: HTTPMethod? = nil,
    flags: GraphRequestFlags? = nil
  ) -> TestGraphRequest {
    capturedGraphPath = graphPath
    capturedParameters = parameters
    capturedTokenString = tokenString
    capturedVersion = version
    capturedHTTPMethod = httpMethod
    capturedFlags = flags

    let newRequest = TestGraphRequest(
      graphPath: graphPath,
      parameters: parameters,
      tokenString: tokenString,
      httpMethod: httpMethod,
      version: version,
      flags: flags
    )

    let returnedRequest = stubbedGraphRequest ?? newRequest
    capturedRequests.append(returnedRequest)
    return returnedRequest
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import FBSDKCoreKit_Basics
import Foundation

// swiftformat:disable indent
@objcMembers
public final class TestInternalUtility: NSObject,
                                        AppAvailabilityChecker,
                                        URLHosting,
                                        AppURLSchemeProviding,
                                        InternalUtilityProtocol {
  // swiftformat:enable indent
  public var validateURLSchemesCalled = false
  public var isFacebookAppInstalled = false
  public var isMessengerAppInstalled = false
  public var stubbedURL: URL?
  public var stubbedAppURL: URL?
  public var stubbedFacebookURL: URL?
  public var capturedURLScheme: String?
  public var capturedURLHost: String?
  public var capturedURLPath: String?
  public var capturedURLQueryParameters: [String: String]?
  public var capturedAppURLHost: String?
  public var capturedAppURLPath: String?
  public var capturedAppURLQueryParameters: [String: String]?
  public var capturedFacebookURLHostPrefix: String?
  public var capturedFacebookURLPath: String?
  public var capturedFacebookURLQueryParameters: [String: String]?
  public var capturedExtensibleParameters: NSMutableDictionary?
  public var isUnity = false
  public var appURLScheme = ""

  public func url(
    withScheme scheme: String,
    host: String,
    path: String,
    queryParameters: [String: String]
  ) throws -> URL {
    capturedURLScheme = scheme
    capturedURLHost = host
    capturedURLPath = path
    capturedURLQueryParameters = queryParameters

    guard let url = stubbedURL else { throw SampleError() }
    return url
  }

  public func facebookURL(
    hostPrefix: String,
    path: String,
    queryParameters: [String: String]
  ) throws -> URL {
    capturedFacebookURLHostPrefix = hostPrefix
    capturedFacebookURLPath = path
    capturedFacebookURLQueryParameters = queryParameters

    guard let url = stubbedFacebookURL else { throw SampleError() }
    return url
  }

  public func appURL(
    withHost host: String,
    path: String,
    queryParameters: [String: String]
  ) throws -> URL {
    capturedAppURLHost = host
    capturedAppURLPath = path
    capturedAppURLQueryParameters = queryParameters

    guard let url = stubbedAppURL else { throw SampleError() }
    return url
  }

  public func registerTransientObject(_ object: Any) {}

  public var unregisterTransientObjectObject: Any?

  public func unregisterTransientObject(_ object: Any) {
    unregisterTransientObjectObject = object
  }

  public func checkRegisteredCanOpenURLScheme(_ urlScheme: String) {}

  public func validateURLSchemes() {
    validateURLSchemesCalled = true
  }

  public func extendDictionary(withDataProcessingOptions parameters: NSMutableDictionary) {
    capturedExtensibleParameters = parameters
  }

  public func hexadecimalString(from data: Data) -> String? {
    nil
  }

  public func validateAppID() {}

  public var stubbedRequiredClientAccessToken: String?

  public func validateRequiredClientAccessToken() -> String {
    stubbedRequiredClientAccessToken ?? ""
  }

  public var capturedExtractPermissionsResponse: [String: Any]?
  public var stubbedGrantedPermissions: [String]?
  public var stubbedDeclinedPermissions: [String]?
  public var stubbedExpiredPermissions: [String]?

  public func extractPermissions(
    fromResponse responseObject: [String: Any],
    grantedPermissions: NSMutableSet,
    declinedPermissions: NSMutableSet,
    expiredPermissions: NSMutableSet
  ) {
    capturedExtractPermissionsResponse = responseObject

    if let granted = stubbedGrantedPermissions {
      grantedPermissions.addObjects(from: granted)
    }

    if let declined = stubbedDeclinedPermissions {
      declinedPermissions.addObjects(from: declined)
    }

    if let expired = stubbedExpiredPermissions {
      expiredPermissions.addObjects(from: expired)
    }
  }

  public func validateFacebookReservedURLSchemes() {}

  public var stubbedFBURLParameters: [String: Any]?

  public func parameters(fromFBURL url: URL) -> [String: Any] {
    stubbedFBURLParameters ?? [:]
  }

  public var bundleForStrings: Bundle { .main }

  public func topMostViewController() -> UIViewController? { nil }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestKeychainStore: NSObject, KeychainStoreProtocol {
  public var service: String?
  public var accessGroup: String?
  public var wasStringForKeyCalled = false
  public var wasSetStringCalled = false
  public var value: String?
  public var key: String?
  public var keychainDictionary: [String: String] = [:]
  public var wasDictionaryForKeyCalled = false
  public var wasSetDictionaryCalled = false

  public convenience init(
    service: String,
    accessGroup: String?
  ) {
    self.init()
    self.service = service
    self.accessGroup = accessGroup
  }

  public func string(forKey key: String) -> String? {
    wasStringForKeyCalled = true
    return keychainDictionary[key]
  }

  public func setString(_ value: String?, forKey key: String, accessibility: CFTypeRef?) -> Bool {
    keychainDictionary[key] = value
    wasSetStringCalled = true
    return true
  }

  public func dictionary(forKey key: String) -> [String: Any]? {
    wasDictionaryForKeyCalled = true
    return [:]
  }

  public func setDictionary(_ value: [String: Any]?, forKey key: String, accessibility: CFTypeRef?) -> Bool {
    wasSetDictionaryCalled = true
    return true
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestKeychainStoreFactory: NSObject, KeychainStoreProviding {

  public var capturedService: String?
  public var capturedAccessGroup: String?
  public var stubbedKeychainStore: TestKeychainStore?

  public func createKeychainStore(
    service: String,
    accessGroup: String?
  ) -> KeychainStoreProtocol {
    capturedService = service
    capturedAccessGroup = accessGroup

    return stubbedKeychainStore ?? TestKeychainStore(
      service: service,
      accessGroup: accessGroup
    )
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

import FBSDKCoreKit_Basics

@objcMembers
public final class TestNotificationCenter: NSObject, NotificationDelivering {

  private let stubbedObject = NSObject()

  public struct ObserverEvidence: Equatable {
    let observer: Any?
    let name: Notification.Name?
    let selector: Selector?
    let object: Any?

    public init(
      observer: Any?,
      name: Notification.Name?,
      selector: Selector?,
      object: Any?
    ) {
      self.observer = observer
      self.name = name
      self.selector = selector
      self.object = object
    }

    public static func == (
      lhs: TestNotificationCenter.ObserverEvidence,
      rhs: TestNotificationCenter.ObserverEvidence
    ) -> Bool {
      lhs.observer as AnyObject === rhs.observer as AnyObject &&
        lhs.name == rhs.name &&
        lhs.selector == rhs.selector &&
        lhs.object as AnyObject === rhs.object as AnyObject
    }
  }

  public var capturedRemovedObservers = [Any]()
  public var capturedPostNames = [NSNotification.Name]()
  public var capturedPostObjects = [Any]()
  public var capturedPostUserInfos = [[String: Any]]()
  public var capturedCompletions = [(Notification) -> Void]()

  public var capturedAddObserverInvocations = [ObserverEvidence]()

  // MARK: Delivering

  public func fb_removeObserver(_ observer: Any) {
    capturedRemovedObservers.append(observer)
  }

  public func fb_addObserver(
    _ observer: Any,
    selector: Selector,
    name: Notification.Name?,
    object: Any?
  ) {
    capturedAddObserverInvocations.append(
      ObserverEvidence(
        observer: observer,
        name: name,
        selector: selector,
        object: object
      )
    )
  }

  public func fb_addObserver(
    forName name: NSNotification.Name?,
    object: Any?,
    queue: OperationQueue?,
    using block: @escaping (Notification) -> Void
  ) -> NSObjectProtocol {
    capturedAddObserverInvocations.append(
      .init(
        observer: nil,
        name: name,
        selector: nil,
        object: object
      )
    )
    capturedCompletions.append(block)

    return stubbedObject
  }

  public func clearTestEvidence() {
    capturedRemovedObservers = []
    capturedPostNames = []
    capturedPostObjects = []
    capturedPostUserInfos = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestProfileProvider: NSObject, ProfileProviding {

  public static var current: Profile?
  public static var stubbedCachedProfile: Profile?

  public static func fetchCachedProfile() -> Profile? {
    stubbedCachedProfile
  }

  public static func reset() {
    current = nil
    stubbedCachedProfile = nil
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objc public enum TestSDKErrorType: Int {
  case general
  case invalidArgument
  case requiredArgument
  case unknown
}

@objcMembers
public final class TestSDKError: NSError {
  public let type: TestSDKErrorType
  public let name: String?
  public let value: Any?
  public let message: String?
  public let underlyingError: Error?

  public static let testErrorDomain = "TestSDKError"
  public static let testErrorCode = 141414

  public init(
    type: TestSDKErrorType,
    domain: String = TestSDKError.testErrorDomain,
    code: Int = TestSDKError.testErrorCode,
    userInfo: [String: Any]? = nil,
    name: String? = nil,
    value: Any? = nil,
    message: String? = nil,
    underlyingError: Error? = nil
  ) {
    self.type = type
    self.name = name
    self.value = value
    self.message = message
    self.underlyingError = underlyingError
    super.init(domain: domain, code: code, userInfo: userInfo)
  }

  @available(*, unavailable)
  public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  public override func copy(with zone: NSZone? = nil) -> Any {
    self
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit_Basics
import Foundation

@objcMembers
public final class TestSessionDataTask: NSObject, NetworkTask {
  public var resumeCallCount = 0
  public var cancelCallCount = 0
  public var stubbedState: URLSessionTask.State = .completed

  // swiftlint:disable:next identifier_name
  public var fb_state: URLSessionTask.State {
    stubbedState
  }

  public func fb_resume() {
    resumeCallCount += 1
  }

  public func fb_cancel() {
    cancelCallCount += 1
  }
}

@objcMembers
public final class TestSessionProvider: NSObject, URLSessionProviding {
  /// A data task to return from `dataTask(with:completion:)`
  public var stubbedDataTask: NetworkTask?
  /// The completion handler to be invoked in the test
  public var capturedCompletion: ((Data?, URLResponse?, Error?) -> Void)?
  /// The url request for the data task
  public var capturedRequest: URLRequest?
  public var dataTaskCallCount = 0

  public func fb_dataTask(
    with request: URLRequest,
    completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
  ) -> NetworkTask {
    dataTaskCallCount += 1
    capturedRequest = request
    capturedCompletion = completionHandler
    return stubbedDataTask ?? TestSessionDataTask()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestSettings: NSObject, SettingsProtocol, SettingsLogging {
  public var isEventDataUsageLimited = false
  public var shouldUseCachedValuesForExpensiveMetadata = false
  public var isAdvertiserIDCollectionEnabled = false
  public var advertiserIDCollectionEnabled = false
  public var appID: String?
  public var clientToken: String?
  public var sdkVersion = ""
  public var userAgentSuffix: String?
  public var displayName: String?
  public var facebookDomainPart: String?
  public var logWarningsCallCount = 0
  public var logIfSDKSettingsChangedCallCount = 0
  public var recordInstallCallCount = 0
  public var appURLSchemeSuffix: String?
  public var graphAPIVersion = FBSDK_DEFAULT_GRAPH_API_VERSION
  public var advertisingTrackingStatus: AdvertisingTrackingStatus = .unspecified
  public var isDataProcessingRestricted = false
  public var isAutoLogAppEventsEnabled = false
  public var installTimestamp: Date?
  public var advertiserTrackingEnabledTimestamp: Date?
  public var isSetATETimeExceedsInstallTime = false
  public var isATETimeSufficientlyDelayed = false
  public var isSKAdNetworkReportEnabled = false
  public var shouldLimitEventAndDataUsage = false
  public var shouldUseTokenOptimizations = true
  public var isGraphErrorRecoveryEnabled = false
  public var graphAPIDebugParameterValue: String?
  public var graphAPIDebugParamValue: String?
  public var isAdvertiserTrackingEnabled = false
  public var advertiserTrackingEnabled = false
  public var loggingBehaviors = Set<LoggingBehavior>()
  public var isCodelessDebugLogEnabled = false
  public var codelessDebugLogEnabled = false
  public static var loggingBehaviors = Set<LoggingBehavior>()
  public var persistableDataProcessingOptions: [String: Any]?

  public func logWarnings() {
    logWarningsCallCount += 1
  }

  public func logIfSDKSettingsChanged() {
    logIfSDKSettingsChangedCallCount += 1
  }

  public func recordInstall() {
    recordInstallCallCount += 1
  }

  public func setDataProcessingOptions(_ options: [String]?) {}

  public func setDataProcessingOptions(_ options: [String]?, country: Int32, state: Int32) {}

  public func reset() {
    appID = nil
    clientToken = nil
    userAgentSuffix = nil
    loggingBehaviors = []
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBAEMKit
import Foundation

public final class TestSKAdNetworkReporter: NSObject, SKAdNetworkReporting {

  public var cutOff = false
  public var reportingEvents: Set<String> = []

  public func shouldCutoff() -> Bool {
    cutOff
  }

  public func isReportingEvent(_ event: String) -> Bool {
    reportingEvents.contains(event)
  }

  public func checkAndRevokeTimer() {}
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit

public final class TestURLHoster: URLHosting {
  public var capturedHost: String?
  public var capturedHostPrefix: String?
  public var capturedPath: String?
  public var capturedQueryParameters: [String: String]?
  public var stubbedURL: URL?

  private var url: URL {
    guard let url = stubbedURL else {
      preconditionFailure("Missing stubbed URL")
    }

    return url
  }

  public init(url: URL? = nil) {
    stubbedURL = url
  }

  public func appURL(
    withHost host: String,
    path: String,
    queryParameters: [String: String]
  ) throws -> URL {
    capturedHost = host
    capturedPath = path
    capturedQueryParameters = queryParameters
    return url
  }

  public func facebookURL(
    hostPrefix: String,
    path: String,
    queryParameters: [String: String]
  ) throws -> URL {
    capturedHostPrefix = hostPrefix
    capturedPath = path
    capturedQueryParameters = queryParameters
    return url
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestURLOpener: NSObject, URLOpener {

  public var capturedRequests = [SuccessBlock]()
  public var capturedURL: URL?
  public var viewController: UIViewController?
  public var wasOpenURLWithoutSVCCalled = false
  public var wasOpenURLWithSVCCalled = false

  public func open(
    _ url: URL,
    sender: URLOpening?,
    handler: @escaping SuccessBlock
  ) {
    capturedURL = url
    capturedRequests.append(handler)
    wasOpenURLWithoutSVCCalled = true
  }

  public func openURLWithSafariViewController(
    url: URL,
    sender: URLOpening?,
    from viewController: UIViewController?,
    handler: @escaping SuccessBlock
  ) {
    capturedURL = url
    capturedRequests.append(handler)
    wasOpenURLWithSVCCalled = true
    self.viewController = viewController
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FBSDKCoreKit
import Foundation

@objcMembers
public final class TestWindowFinder: NSObject, _WindowFinding {
  public var wasFindWindowCalled = false
  public var window: UIWindow?

  public convenience init(window: UIWindow) {
    self.init()

    self.window = window
  }

  public func findWindow() -> UIWindow? {
    wasFindWindowCalled = true
    return window
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

@objcMembers
public final class UserDefaultsSpy: UserDefaults {
  public var capturedObjectRetrievalKeys = [String]()
  public var capturedSetObjectKeys = [String]()
  public var capturedObjectRetrievalKey: String?
  public var capturedSetObjectKey: String?
  public var capturedValues = [String: Any]()

  public var stringForKeyCallback: ((String) -> String)? = { $0 }

  public override func string(forKey defaultName: String) -> String? {
    stringForKeyCallback?(defaultName)
  }

  public override func object(forKey defaultName: String) -> Any? {
    capturedObjectRetrievalKey = defaultName
    capturedObjectRetrievalKeys.append(defaultName)
    return capturedValues[defaultName]
  }

  public override func set(_ value: Any?, forKey defaultName: String) {
    capturedValues[defaultName] = value
    capturedSetObjectKeys.append(defaultName)
    capturedSetObjectKey = defaultName
  }
}


/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import FBSDKCoreKit
import FBSDKGamingServicesKit
import Foundation

@objc
public protocol FBSDKShareTournamentDialogDelegate: AnyObject {
    func didComplete(dialog: FBSDKShareTournamentDialog, tournament: FBSDKTournament)
    func didFail(withError error: Error, dialog: FBSDKShareTournamentDialog)
    func didCancel(dialog: FBSDKShareTournamentDialog)
}

/// An internal wrapper for sharing tournaments via dialog
@objcMembers
public final class FBSDKShareTournamentDialog: NSObject, ShareTournamentDialogDelegate {
    weak var delegate: FBSDKShareTournamentDialogDelegate?
    private var dialog: ShareTournamentDialog?

    public init(delegate: FBSDKShareTournamentDialogDelegate) {
        self.delegate = delegate
        super.init()
        dialog = ShareTournamentDialog(delegate: self)
    }

    public func show(score: Int, tournamentID: String) throws {
        try dialog?.show(score: score, tournamentID: tournamentID)
    }

    public func show(
        initialScore: Int,
        title: String? = nil,
        endTime: Date? = nil,
        scoreType: Int,
        sortOrder: Int,
        payload: String? = nil
    ) throws {
        let currentConfig = TournamentConfig(
            title: title,
            endTime: endTime,
            scoreType: scoreType == 0 ? .numeric : .time,
            sortOrder: sortOrder == 0 ? .higherIsBetter : .lowerIsBetter,
            image: nil,
            payload: payload
        )
        try dialog?.show(initialScore: initialScore, config: currentConfig)
    }

    // MARK: FBSDKShareTournamentDialogDelegate
    public func didComplete(dialog: ShareTournamentDialog, tournament: Tournament) {
        delegate?.didComplete(dialog: self, tournament: FBSDKTournament(tournament: tournament))
    }

    public func didFail(withError error: Error, dialog: ShareTournamentDialog) {
        delegate?.didFail(withError: error, dialog: self)
    }

    public func didCancel(dialog: ShareTournamentDialog) {
        delegate?.didCancel(dialog: self)
    }
}


/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import FBSDKGamingServicesKit
import Foundation

/// An internal representation of tournament graph objects.
@objcMembers
public final class FBSDKTournament: NSObject {

    /// The unique ID that is associated with this tournament.
    public internal(set) var identifier: String

    /**
     Timestamp when the tournament ends.
     If the expiration is in the past, then the tournament is already finished and has expired.
     */
    public internal(set) var endTime: Date?

    /// Title of the tournament provided upon the creation of the tournament.
    public internal(set) var title: String?

    /// Payload of the tournament provided upon the creation of the tournament.
    public var payload: String?

    public convenience init(tournament: Tournament) {
        self.init(
            identifier: tournament.identifier,
            endTime: tournament.endTime,
            title: tournament.title,
            payload: tournament.payload
        )
    }

    public var toDictionary: [String: String] {
        var dictionary = ["tournament_id": identifier]
        if let endTime = endTime {
            dictionary["end_time"] = "\(endTime.timeIntervalSince1970)"
        }
        dictionary["tournament_title"] = title
        dictionary["payload"] = payload
        return dictionary
    }

    public init(
        identifier: String,
        endTime: Date? = nil,
        title: String? = nil,
        payload: String? = nil
    ) {
        self.identifier = identifier
        self.endTime = endTime
        self.title = title
        self.payload = payload
    }
}


/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import FBSDKCoreKit
import FBSDKGamingServicesKit
import Foundation

/// An internal class for fetching tournament objects.
@objcMembers
public final class FBSDKTournamentFetcher: NSObject {

  public override init() {
      super.init()
  }

  /**
      Attempts to fetch all the tournaments where the current logged in user is a participant ;
   - Parameter completionHandler: The caller's completion handler to invoke once the graph request is complete
   */
  public func fetchTournaments(completionHandler: @escaping ([FBSDKTournament]?, Error?) -> Void) {
    TournamentFetcher()
          .fetchTournaments { result in
      switch result {
      case let .success(tournaments):
        completionHandler(tournaments.map(FBSDKTournament.init), nil)
      case let .failure(error):
        completionHandler(nil, error)
      }
    }
  }
}


/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
 * copy, modify, and distribute this software in source code or binary form for use
 * in connection with the web services and APIs provided by Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use of
 * this software is subject to the Facebook Developer Principles and Policies
 * [http://developers.facebook.com/policy/]. This copyright notice shall be
 * included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import FBSDKCoreKit
import FBSDKGamingServicesKit
import Foundation

/// An internal class for fetching tournament objects.
@objcMembers
public final class FBSDKTournamentUpdater: NSObject {

    public override init() {
        super.init()
    }

  /**
   Updates the given tournament with the given score
   - Parameter tournamentID: The ID of the tournament you want to update
   - Parameter score: The new score to update within the tournament
   - Parameter completionHandler: The caller's completion handler to invoke once the graph request is complete. Completes with `true` if successful.
   */
  public func update(
    tournamentID: String,
    score: Int,
    completionHandler: @escaping (Bool, Error?) -> Void
  ) {
    guard !tournamentID.isEmpty else {
      return completionHandler(false, TournamentUpdaterError.invalidTournamentID)
    }
    TournamentUpdater()
      .update(tournamentID: tournamentID, score: score) { result in
        switch result {
        case let .success(success):
          completionHandler(success, nil)
        case let .failure(error):
          completionHandler(false, error)
        }
      }
  }

  /**
   Updates the given tournament with the given score
   - Parameter tournament: The tournament you want to update
   - Parameter score: The new score to update within the tournament
   - Parameter completionHandler: The caller's completion handler to invoke once the graph request is complete. Completes with `true` if successful.
   */

  public func update(
    tournament: FBSDKTournament,
    score: Int,
    completionHandler: @escaping (Bool, Error?) -> Void
  ) {
    update(tournamentID: tournament.identifier, score: score, completionHandler: completionHandler)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import FlipperKit
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    window = UIWindow()

    let client = FlipperClient.shared()
    let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
    client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper))

    client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
    client?.add(FlipperKitExamplePlugin.sharedInstance())
    client?.add(FKUserDefaultsPlugin(suiteName: nil))
    client?.start()

    let storyboard = UIStoryboard(name: "MainStoryBoard", bundle: nil)
    let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController")
    let navigationController = UINavigationController(rootViewController: mainViewController)

    navigationController.navigationBar.topItem?.title = "SampleFlipper"
    navigationController.navigationBar.isTranslucent = false

    window?.rootViewController = navigationController
    window?.makeKeyAndVisible()

    // Use NSLog since Flipepr doesn't capture print() by default
    NSLog("Hello from Flipper in a Swift app!")

    return true
  }

  func applicationWillResignActive(_ application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
  }

  func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
  }

  func applicationWillEnterForeground(_ application: UIApplication) {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
  }

  func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
  }

  func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit
import FlipperKit

class CommunicationDemoViewController: UIViewController, UITableViewDataSource, FlipperKitExampleCommunicationResponderDelegate {
  @IBOutlet weak var messageField: UITextField!
  @IBOutlet weak var tableView: UITableView!
  var messageArray: [String] = []

  override func viewDidLoad() {
    super.viewDidLoad()
    FlipperKitExamplePlugin.sharedInstance()?.delegate = self
  }

  @IBAction func tappedTriggerNotification(_ sender: UIButton) {
  FlipperKitExamplePlugin.sharedInstance()?.triggerNotification();
  }

  @IBAction func tappedSendMessage(_ sender: UIButton) {
    if let message = self.messageField.text {
      FlipperKitExamplePlugin.sharedInstance()?.sendMessage(message);
    }
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reusableCell", for: indexPath)
    cell.textLabel?.text = messageArray[indexPath.row]
    return cell
  }

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return messageArray.count;
  }

  func messageReceived(_ msg: String!) {
    messageArray.append(msg)
    DispatchQueue.main.async { [weak self] in
      self?.tableView.reloadData();
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

class NetworkViewController: UIViewController {

  @IBAction func tappedGetAPI(_ sender: UIButton) {
    let getURL = URL(string: "https://demo9512366.mockable.io/FlipperGet")!
    let dataTask = URLSession.shared.dataTask(with: getURL){ [weak self] (data, response, error) in
      guard let strongSelf = self else { return }
      guard let dataUnwrapped = data else {
        strongSelf.showAlert(message: "Received no data in GET API")
        return
      }

      if let errorUnwrapped = error {
        strongSelf.showAlert(message: "Received error in GET API Error:\(errorUnwrapped.localizedDescription)")
        return
      }

      let dict = try? JSONSerialization.jsonObject(with: dataUnwrapped, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as? [String: String]
      // As sonar cannot detect print() in Logs
      NSLog("MSG-GET: \(dict?["msg"] ?? "Did not find msg key in the received response")")
      strongSelf.showAlert(message: "Received response from GET API, please check the sonar network plugin for detailed response")
    }
    dataTask.resume()
  }

  @IBAction func tappedPOSTAPI(_ sender: UIButton) {
    guard let postURL = URL(string: "https://demo9512366.mockable.io/FlipperPost") else {
      showAlert(message: "Check the POST URL")
      return
    }
    var postRequest = URLRequest(url: postURL)
    postRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    postRequest.addValue("application/json", forHTTPHeaderField: "Accept")

    let dict = ["app" : "Flipper", "remarks": "Its Awesome"]
    postRequest.httpBody = try! JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions.init(rawValue: 0))
    postRequest.httpMethod = "POST"
    let dataTask = URLSession.shared.dataTask(with: postRequest){ [weak self] (data, response, error) in
      guard let strongSelf = self else { return }
      guard let dataUnwrapped = data else {
        strongSelf.showAlert(message: "Received no data in POST API")
        return
      }

      if let errorUnwrapped = error {
        strongSelf.showAlert(message: "Received error in POST API Error:\(errorUnwrapped.localizedDescription)")
        return
      }

      let dict = try? JSONSerialization.jsonObject(with: dataUnwrapped, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as? [String: String]
      // As sonar cannot detect print() in Logs
      NSLog("MSG-POST: \(dict?["msg"] ?? "Did not find msg key in the received response")")
      strongSelf.showAlert(message: "Received response from POST API, please check the sonar network plugin for detailed response")
    }
    dataTask.resume()
  }

  @IBAction func tappedFetchFBLitho(_ sender: UIButton) {
    let imageURL = URL(string: "https://raw.githubusercontent.com/facebook/litho/master/docs/static/logo.png")!
    let dataTask = URLSession.shared.dataTask(with: imageURL){ [weak self] (data, response, error) in
      guard let strongSelf = self else { return }
      guard let _ = data else {
        strongSelf.showAlert(message: "Received no data in Images API")
        return
      }

      if let errorUnwrapped = error {
        strongSelf.showAlert(message: "Received error in Images API Error:\(errorUnwrapped.localizedDescription)")
        return
      }

      // As sonar cannot detect print() in Logs
      NSLog("Got Image")
      strongSelf.showAlert(message: "Received Litho Image")
    }
    dataTask.resume()
  }

  func showAlert(message: String) {
    DispatchQueue.main.async {
      let alertController = UIAlertController.init(title: "Flipper", message: message, preferredStyle: .alert);
      let alertAction = UIAlertAction(title: "Okay", style: UIAlertAction.Style.default, handler: nil)
      alertController.addAction(alertAction)
      self.present(alertController, animated: true, completion: nil)
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

class UserDefaultsViewController: UIViewController {

    @IBOutlet weak var keyTextField: UITextField!
    @IBOutlet weak var valueTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    @IBAction func tappedSave(_ sender: Any) {
        UserDefaults.standard.set(self.valueTextField.text ?? "", forKey: self.keyTextField.text ?? "")
    }

}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }

}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit
import FlipperKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    let client = FlipperClient.shared()
    let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())
    // If you want to debug componentkit view in swift, otherwise you can omit the next line
    FlipperKitLayoutComponentKitSupport.setUpWith(layoutDescriptorMapper)
    client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))
    client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))
    client?.add(FKUserDefaultsPlugin.init(suiteName: nil))
    client?.add(SeaMammalsPlugin(MarineMammal.defaultList))
    client?.start()

    return true
  }

  func applicationWillResignActive(_ application: UIApplication) {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
  }

  func applicationDidEnterBackground(_ application: UIApplication) {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
  }

  func applicationWillEnterForeground(_ application: UIApplication) {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
  }

  func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
  }

  func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  }

}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import FlipperKit

class SeaMammalsPlugin: NSObject, FlipperPlugin {
  var connection: FlipperConnection? = nil
  let mammals: [MarineMammal]

  init(_ marineMammals: [MarineMammal]) {
      mammals = marineMammals
  }

  func identifier() -> String! {
    return "sea-mammals"
  }

  func didConnect(_ connection: FlipperConnection!) {
    self.connection = connection
    for (index, mammal) in mammals.enumerated() {
      connection.send("newRow", withParams: ["id": index, "title": mammal.name, "url": mammal.image.absoluteString])
    }
  }

  func didDisconnect() {
    connection = nil;
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

class ViewController: UIViewController, UITableViewDataSource {
  let marineMammals: [MarineMammal] = MarineMammal.defaultList

  override func viewDidLoad() {
    super.viewDidLoad()
  }

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return marineMammals.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MarineMammalCell", for: indexPath)
    guard let mammalCell = cell as? MarineMammalCell else {
      fatalError("Wrong cell identifier")
    }
    mammalCell.populate(marineMammal: marineMammals[indexPath.row])
    return mammalCell
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import UIKit

struct MarineMammal {
  let name: String
  let image: URL
  static let defaultList: [MarineMammal] = [
    MarineMammal(name: "Polar Bear", image: URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Ursus_maritimus_4_1996-08-04.jpg/190px-Ursus_maritimus_4_1996-08-04.jpg")!),
    MarineMammal(name: "Sea Otter", image: URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Sea_otter_cropped.jpg/220px-Sea_otter_cropped.jpg")!),
    MarineMammal(name: "West Indian Manatee", image: URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/FL_fig04.jpg/230px-FL_fig04.jpg")!),
    MarineMammal(name: "Bottlenose Dolphin", image: URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Tursiops_truncatus_01.jpg/220px-Tursiops_truncatus_01.jpg")!),
  ]
}

class MarineMammalCell: UITableViewCell {

  @IBOutlet weak var photo: UIImageView!
  @IBOutlet weak var name: UILabel!

  func populate(marineMammal: MarineMammal) {
    let task = URLSession.shared.dataTask(with: marineMammal.image) { [weak self] (data, response, error) in
      if let unwrappedError = error {
        print(unwrappedError)
        return
      }

      guard let unwrappedData = data else {
        print("No Image data received")
        return
      }
      let image = UIImage(data: unwrappedData)

      guard let unwrappedImage = image else {
        print("Failed to instantiate an image from Image data")
        return
      }
      DispatchQueue.main.async {
        self?.photo.image = unwrappedImage
      }
    }
    task.resume()
    self.name.text = marineMammal.name
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Fuzzilli

let hermesProfile = Profile(
    getProcessArguments:  { (randomizingArguments: Bool) -> [String] in
      var args = ["--reprl"]

      guard randomizingArguments else { return args }

      if probability(0.5) { args.append("--compile") }
      if probability(0.5) { args.append("--lazy-compilation") }
      if probability(0.5) { args.append("--eager-compilation") }
      if probability(0.5) { args.append("--optimize") }
      if probability(0.5) { args.append("--async-break") }
      if probability(0.5) { args.append("--block-scoping") }
      if probability(0.5) { args.append("--random-mem-layout") }

      return args
    },

    processEnv: ["UBSAN_OPTIONS": "handle_segv=0"],

    maxExecsBeforeRespawn: 1000,

    timeout: 2000,

    codePrefix: """
                function main(){
                """,

    codeSuffix: """
                }; main();
                """,

    ecmaVersion: ECMAScriptVersion.es6,

    crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"],

    additionalCodeGenerators: [],

    additionalProgramTemplates: WeightedList<ProgramTemplate>([]),

    disabledCodeGenerators: ["AsyncArrowFunctionGenerator", "AsyncGeneratorFunctionGenerator", "ClassGenerator", "WithStatementGenerator", "JITFunctionGenerator", "GrowableSharedArrayBufferGenerator"],

    additionalBuiltins: [
        "gc"                                             : .function([] => .undefined),
        "print"                                          : .function([.plain(.anything)] => .undefined),
        "HermesInternal.enqueueJob"                      : .function([.plain(.function())] => .undefined),
        "HermesInternal.setPromiseRejectionTrackingHook" : .function([.plain(.function())] => .undefined),
        "HermesInternal.enablePromiseRejectionTracker"   : .function([.plain(.anything)] => .anything),
        "HermesInternal.getEpilogues"                    : .function([] => .iterable),
        "HermesInternal.getInstrumentedStats"            : .function([] => .object(ofGroup: "Object", withProperties: ["js_VMExperiments", "js_numGCs", "js_gcCPUTime", "js_gcTime", "js_totalAllocatedBytes", "js_allocatedBytes", "js_heapSize", "js_mallocSizeEstimate", "js_vaSize", "js_markStackOverflows"])),
        "HermesInternal.getRuntimeProperties"            : .function([] => .object(ofGroup: "Object", withProperties: ["Snapshot VM", "Bytecode Version", "Builtins Frozen", "VM Experiments", "Build", "GC", "OSS Release Version", "CommonJS Modules"])),
        "HermesInternal.ttiReached"                      : .function([] => .undefined),
        "HermesInternal.getFunctionLocation"             : .function([.plain(.function())] => .object(ofGroup: "Object", withProperties: ["isNative", "lineNumber", "columnNumber", "fileName"])),

        // The methods below are disabled since they are not very interesting to fuzz
        // "HermesInternal.hasPromise"                   : .function([] => .boolean),
        // "HermesInternal.useEngineQueue"               : .function([] => .boolean),
        // "HermesInternal.ttrcReached"                  : .function([] => .undefined),
    ]
)


// Copyright 2019 Google LLC
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Fuzzilli

struct Profile {
    let getProcessArguments: (_: Bool) -> [String]
    let processEnv: [String : String]
    let maxExecsBeforeRespawn: Int
    // Timeout is in milliseconds.
    let timeout: Int
    let codePrefix: String
    let codeSuffix: String
    let ecmaVersion: ECMAScriptVersion

    // JavaScript code snippets that cause a crash in the target engine.
    // Used to verify that crashes can be detected.
    let crashTests: [String]

    let additionalCodeGenerators: [(CodeGenerator, Int)]
    let additionalProgramTemplates: WeightedList<ProgramTemplate>

    let disabledCodeGenerators: [String]

    let additionalBuiltins: [String: JSType]
}

let profiles = [
    "hermes": hermesProfile,
]


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

private class BundleFinder {}

enum TestFixtures {

  static let xctestBinary = Bundle(for: BundleFinder.self)
    .path(forResource: "xctest", ofType: nil)!

  static let assetsdCrashPathWithCustomDeviceSet = Bundle(for: BundleFinder.self)
    .path(forResource: "assetsd_custom_set", ofType: "crash")!

  static let appCrashPathWithDefaultDeviceSet = Bundle(for: BundleFinder.self)
    .path(forResource: "app_default_set", ofType: "crash")!

  static let appCrashPathWithCustomDeviceSet = Bundle(for: BundleFinder.self)
    .path(forResource: "app_custom_set", ofType: "crash")!

  static let agentCrashPathWithCustomDeviceSet = Bundle(for: BundleFinder.self)
    .path(forResource: "agent_custom_set", ofType: "crash")!

  static let appCrashWithJSONFormat = Bundle(for: BundleFinder.self)
    .path(forResource: "xctest-concated-json-crash", ofType: "ips")!
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import XCTest

@testable import FBControlCore

// swiftlint:disable implicitly_unwrapped_optional
final class FBArchitectureProcessAdapterTests: XCTestCase {

  var adapter: FBArchitectureProcessAdapter!
  var processConfiguration: FBProcessSpawnConfiguration<AnyObject, AnyObject, AnyObject>!
  let targetQueue = DispatchQueue(label: "test_queue", qos: .userInteractive)
  var tmpDir: FBTemporaryDirectory!

  func getArchsInBinary(binary: String) throws -> String {
    try FBProcessBuilder<AnyObject, NSString, AnyObject>
      .withLaunchPath("/usr/bin/lipo", arguments: ["-archs", binary])
      .withStdOutInMemoryAsString()
      .withStdErrToDevNull()
      .runUntilCompletion(withAcceptableExitCodes: [0])
      .onQueue(targetQueue, map: { p in p.stdOut ?? "" })
      .await(withTimeout: 2) as! String // swiftlint:disable:this force_cast
  }

  func adaptedProcess(requested: Set<FBArchitecture>, host: Set<FBArchitecture>) throws -> FBProcessSpawnConfiguration<AnyObject, AnyObject, AnyObject> {
    let tmpdir = tmpDir.temporaryDirectory()
    return try adapter
      .adaptProcessConfiguration(processConfiguration, toAnyArchitectureIn: requested, hostArchitectures: host, queue: targetQueue, temporaryDirectory: tmpdir)
      .await(withTimeout: 10)
  }

  override func setUp() {
    tmpDir = .init(logger: FBControlCoreLoggerFactory.systemLoggerWriting(toStderr: true, withDebugLogging: true))
    adapter = .init()
    processConfiguration = .init(launchPath: TestFixtures.xctestBinary, arguments: [], environment: [:], io: FBProcessIO<AnyObject, AnyObject, AnyObject>.outputToDevNull(), mode: .posixSpawn)
  }

  override func tearDown() {
    tmpDir.cleanOnExit()
  }

  func testBinaryIsThinnedDownTox86_64OnArm64Host() throws {
    let newConf = try adaptedProcess(requested: [.X86_64], host: [.X86_64, .arm64])
    XCTAssertNotEqual(newConf.launchPath, processConfiguration.launchPath)
    XCTAssertEqual(try getArchsInBinary(binary: newConf.launchPath), "x86_64")
  }

  func testBinaryIsThinnedDownTox86_64Onx86_64Host() throws {
    let newConf = try  adaptedProcess(requested: [.X86_64, .arm64], host: [.X86_64])
    XCTAssertNotEqual(newConf.launchPath, processConfiguration.launchPath)
    XCTAssertEqual(try getArchsInBinary(binary: newConf.launchPath), "x86_64")
  }

  func testArm64ArchTakesPreference() throws {
    let newConf = try adaptedProcess(requested: [.X86_64, .arm64], host: [.X86_64, .arm64])
    XCTAssertNotEqual(newConf.launchPath, processConfiguration.launchPath)
    XCTAssertEqual(try getArchsInBinary(binary: newConf.launchPath), "arm64")
  }

  func testMismatchFails() throws {
    XCTAssertThrowsError(try adaptedProcess(requested: [.arm64], host: [.X86_64]))
  }

  func testDyldFrameworkPathEnvVariableInProcessInfo() throws {
    let process = try adaptedProcess(requested: [.X86_64], host: [.arm64, .X86_64])
    let frameworkPath = try XCTUnwrap(process.environment["DYLD_FRAMEWORK_PATH"])
    XCTAssertFalse(frameworkPath.isEmpty)
  }
}