hunk.code_window: NSString *ABI14_0_0EXWebBrowserErrorCode = @"ABI14_0_0EXWebBrowser";
   @implementation ABI14_0_0EXWebBrowser
   {
     ABI14_0_0RCTPromiseResolveBlock _redirectResolve;
     ABI14_0_0RCTPromiseRejectBlock _redirectReject;
     UIStatusBarStyle _initialStatusBarStyle;
   }
   ABI14_0_0RCT_EXPORT_MODULE(ExponentWebBrowser)
  
hunk.labels: keep keep keep keep keep replace replace keep keep keep keep
hunk.file_path: ios/versioned-react-native/ABI14_0_0/Exponent/Modules/Api/ABI14_0_0EXWebBrowser.m
hunk.type: replace
file: #include <gtest/gtest.h>
  
  #include <cxxReactABI15_0_0/ABI15_0_0CxxMessageQueue.h>
  
  #include <mutex>
  #include <condition_variable>
  
  using namespace facebook::ReactABI15_0_0;
  using detail::EventFlag;
  using time_point = EventFlag::time_point;
  
  using std::chrono::milliseconds;
  
  namespace {
  time_point now() {
    return std::chrono::steady_clock::now();
  }
  
  std::shared_ptr<CxxMessageQueue> createAndStartQueue(EventFlag& finishedFlag) {
    auto q = std::make_shared<CxxMessageQueue>();
    std::thread t([q, &finishedFlag] () mutable {
        auto loop = CxxMessageQueue::getRunLoop(q);
        // Note: make sure that no stack frames above loop() have a strong reference to q.
        q.reset();
        loop();
        finishedFlag.set();
      });
    t.detach();
    return q;
  }
  
  // This is just used to start up a queue for a test and make sure that it is
  // actually shut down after the test.
  struct QueueWithThread {
    QueueWithThread() {
      queue = createAndStartQueue(done);
    }
  
    ~QueueWithThread() {
      queue->quitSynchronous();
      queue.reset();
      if (!done.wait_until(now() + milliseconds(300))) {
        ADD_FAILURE() << "Queue did not exit";
      }
    }
  
    EventFlag done;
    std::shared_ptr<CxxMessageQueue> queue;
  };
  }
  
  TEST(CxxMessageQueue, TestQuit) {
    EventFlag done;
    auto q = createAndStartQueue(done);
    q->quitSynchronous();
    if (!done.wait_until(now() + milliseconds(300))) {
      FAIL() << "Queue did not exit runloop after quitSynchronous";
    }
  }
  
  TEST(CxxMessageQueue, TestPostTask) {
    QueueWithThread qt;
    auto q = qt.queue;
  
    EventFlag flag;
    q->runOnQueue([&] {
        flag.set();
      });
    flag.wait();
  }
  
  TEST(CxxMessageQueue, TestPostTaskMultiple) {
    QueueWithThread qt;
    auto q = qt.queue;
  
    std::vector<EventFlag> vec(10);
    for (int i = 0; i < 10; i++) {
      q->runOnQueue([&, i] {
          vec[i].set();
        });
    }
    for (int i = 0; i < 10; i++) {
      vec[i].wait();
    }
  }
  
  TEST(CxxMessageQueue, TestQueuedTaskOrdering) {
    QueueWithThread qt;
    auto q = qt.queue;
  
    // Block the runloop so we can get some queued tasks.
    EventFlag wait;
    q->runOnQueue([&] {
        wait.wait();
      });
  
    // These tasks should run in order.
    int failed = -1;
    int i = 0;
    for (int j = 0; j < 10; j++) {
      q->runOnQueue([&, j] {
          if (i != j) {
            failed = j;
          }
          i++;
        });
    }
    wait.set();
  
    // Flush the queue.
    q->runOnQueueSync([&] {});
  
    ASSERT_EQ(failed, -1);
    ASSERT_EQ(i, 10);
  }
  
  TEST(CxxMessageQueue, TestDelayedTaskOrdering) {
    QueueWithThread qt;
    auto q = qt.queue;
  
    // Block the runloop so we can get some queued tasks.
    EventFlag wait;
    q->runOnQueue([&] {
        wait.wait();
      });
  
    int ids[] = {8, 4, 6, 1, 3, 2, 9, 5, 0, 7};
  
    int failed = -1;
    int i = 0;
    EventFlag done;
    // If this loop actually takes longer than the difference between delays, the
    // ordering could get screwed up :/
    for (int j = 0; j < 10; j++) {
      q->runOnQueueDelayed([&, j] {
          if (i != ids[j]) {
            failed = j;
          }
          i++;
          if (ids[j] == 9) {
            done.set();
          }
        }, 50 + 10 * ids[j]);
    }
    wait.set();
    done.wait();
  
    ASSERT_EQ(failed, -1);
    ASSERT_EQ(i, 10);
  }
  