Repository: airbnb/lottie-ios
File: Tests/PerformanceTests.swift (Swift)

Code before:
import XCTest

@testable import Lottie

// MARK: - PerformanceTests

final class PerformanceTests: XCTestCase {

  // MARK: Internal

  func testAnimationViewSetup_simpleAnimation() {
    // Compare the performance of displaying this simple animation in the two animation engines
    let ratio = compareEngineSetupPerformance(for: simpleAnimation, iterations: 2000)

    // This is basically a snapshot test for the performance of the Core Animation engine
    // compared to the Main Thread engine. Currently, the Core Animation engine is
    // about 1.6x slower than the Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.6, accuracy: 0.3)
  }

  func testAnimationViewSetup_complexAnimation() {
    let ratio = compareEngineSetupPerformance(for: complexAnimation, iterations: 500)
    XCTAssertEqual(ratio, 1.6, accuracy: 0.3)
  }

  func testAnimationViewScrubbing_simpleAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: simpleAnimation, iterations: 1000)
    XCTAssertEqual(ratio, 0.1, accuracy: 0.1)
  }

  func testAnimationViewScrubbing_complexAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: complexAnimation, iterations: 1000)
    XCTAssertEqual(ratio, 0.1, accuracy: 0.1)
  }

  // MARK: Private

  private let simpleAnimation = Animation.named(
    "loading_dots_1",
    bundle: .module,
    subdirectory: "Samples/LottieFiles")!

  private let complexAnimation = Animation.named(
    "LottieLogo2",
    bundle: .module,
    subdirectory: "Samples")!

  /// Compares initializing the given animation with both the Main Thread and Core Animation engine,
  /// and returns the ratio of how much slower the Core Animation is than the Main Thread engine
  private func compareEngineSetupPerformance(for animation: Animation, iterations: Int) -> Double {
    let mainThreadEnginePerformance = measurePerformance {

Review comment (suggestion):
Before the optimizations elsewhere in this PR, this number was `3.0` -- so these optimizations made quite the difference for complex animations!

I've seen this be as low as `1.4` locally, but I kept the tolerance a bit high to give leeway in CI.

Code after:
import XCTest

@testable import Lottie

// MARK: - PerformanceTests

final class PerformanceTests: XCTestCase {

  // MARK: Internal

  func testAnimationViewSetup_simpleAnimation() {
    // Compare the performance of displaying this simple animation in the two animation engines
    let ratio = compareEngineSetupPerformance(for: simpleAnimation, iterations: 2000)

    // This is basically a snapshot test for the performance of the Core Animation engine
    // compared to the Main Thread engine. Currently, the Core Animation engine is
    // about the same speed as the Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.0, accuracy: 0.15)
  }

  func testAnimationViewSetup_complexAnimation() {
    let ratio = compareEngineSetupPerformance(for: complexAnimation, iterations: 500)

    // The Core Animation engine is currently about 1.6x slower than the
    // Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.6, accuracy: 0.3)
  }

  func testAnimationViewScrubbing_simpleAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: simpleAnimation, iterations: 2000)
    XCTAssertEqual(ratio, 0.002, accuracy: 0.001)
  }

  func testAnimationViewScrubbing_complexAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: complexAnimation, iterations: 2000)
    XCTAssertEqual(ratio, 0.0005, accuracy: 0.00035)
  }

  override func setUp() {
    TestHelpers.performanceTestsAreRunning = true
  }

  override func tearDown() {
    TestHelpers.performanceTestsAreRunning = false
  }

  // MARK: Private

  private let simpleAnimation = Animation.named(
    "loading_dots_1",
    bundle: .module,