1// Copyright 2014 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "base/test/ios/wait_util.h" 6 7#import <Foundation/Foundation.h> 8 9#include "base/check.h" 10#include "base/mac/scoped_nsobject.h" 11#include "base/run_loop.h" 12#include "base/test/test_timeouts.h" 13#include "base/timer/elapsed_timer.h" 14 15namespace base { 16namespace test { 17namespace ios { 18 19bool WaitUntilConditionOrTimeout(TimeDelta timeout, ConditionBlock condition) { 20 NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:timeout.InSecondsF()]; 21 bool success = condition(); 22 while (!success && [[NSDate date] compare:deadline] != NSOrderedDescending) { 23 base::test::ios::SpinRunLoopWithMaxDelay(kSpinDelaySeconds); 24 success = condition(); 25 } 26 return success; 27} 28 29TimeDelta TimeUntilCondition(ProceduralBlock action, 30 ConditionBlock condition, 31 bool run_message_loop, 32 TimeDelta timeout) { 33 ElapsedTimer timer; 34 if (action) 35 action(); 36 if (timeout.is_zero()) 37 timeout = TestTimeouts::action_timeout(); 38 constexpr TimeDelta kSpinDelay(Milliseconds(10)); 39 bool condition_evaluation_result = false; 40 while (timer.Elapsed() < timeout && 41 (!condition || !(condition_evaluation_result = condition()))) { 42 SpinRunLoopWithMaxDelay(kSpinDelay); 43 if (run_message_loop) 44 RunLoop().RunUntilIdle(); 45 } 46 const TimeDelta elapsed = timer.Elapsed(); 47 // If DCHECK is ever hit, check if |action| is doing something that is 48 // taking an unreasonably long time, or if |condition| does not come 49 // true quickly enough. Increase |timeout| only if necessary. 50 DCHECK(!condition || condition_evaluation_result); 51 return elapsed; 52} 53 54void WaitUntilCondition(ConditionBlock condition, 55 bool run_message_loop, 56 TimeDelta timeout) { 57 TimeUntilCondition(nil, condition, run_message_loop, timeout); 58} 59 60void WaitUntilCondition(ConditionBlock condition) { 61 WaitUntilCondition(condition, false, TimeDelta()); 62} 63 64void SpinRunLoopWithMaxDelay(TimeDelta max_delay) { 65 scoped_nsobject<NSDate> beforeDate( 66 [[NSDate alloc] initWithTimeIntervalSinceNow:max_delay.InSecondsF()]); 67 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 68 beforeDate:beforeDate]; 69} 70 71void SpinRunLoopWithMinDelay(TimeDelta min_delay) { 72 ElapsedTimer timer; 73 while (timer.Elapsed() < min_delay) { 74 SpinRunLoopWithMaxDelay(Milliseconds(10)); 75 } 76} 77 78} // namespace ios 79} // namespace test 80} // namespace base 81