FakeXCTestCase.m   [plain text]


//
//  FakeXCTest
//
//  Copyright (c) 2014 Apple. All rights reserved.
//

#import <mach/mach.h>
#import <mach/mach_time.h>
#import "FakeXCTestCase.h"

static uint64_t
relative_nano_time(void)
{
    static uint64_t factor;
    uint64_t now;

    now = mach_absolute_time();

    if (factor == 0) {
        mach_timebase_info_data_t base;
        (void)mach_timebase_info(&base);
        factor = base.numer / base.denom;
    }

    return now * factor;
}

#define MAXTESTRUN 5

@interface XCTestCase () {
    uint64_t _start;
    uint64_t _testRuns[MAXTESTRUN];
    unsigned _testrun;

}
@end

@implementation XCTestCase

+ (NSArray *)defaultPerformanceMetrics {
    return NULL;
}

- (void)setUp {
}
- (void)tearDown {
}

- (void)measureBlock:(void (^)(void))block
{
    [self measureMetrics:@[ [XCTestCase defaultPerformanceMetrics] ] automaticallyStartMeasuring:YES forBlock:block];
}


- (void)measureMetrics:(NSArray *)metrics automaticallyStartMeasuring:(BOOL)automaticallyStartMeasuring forBlock:(void (^)(void))block;
{
    unsigned long n;
    uint64_t sum = 0, mean;
    double stddiv = 0.0;

    (void)metrics;

    for (_testrun = 0; _testrun < MAXTESTRUN; _testrun++) {
        _start = 0;
        if (automaticallyStartMeasuring)
            [self startMeasuring];
        block();
        if (automaticallyStartMeasuring)
            [self stopMeasuring];
    }
    printf("TIME %d runs [", MAXTESTRUN);
    for (n = 0; n < MAXTESTRUN; n++) {
        printf("%0.2lf%s", (double)_testRuns[n] / NSEC_PER_SEC,
               n == MAXTESTRUN - 1 ? "" : " ");
        sum += _testRuns[n];
    }
    mean = sum / MAXTESTRUN;

    for (n = 0; n < MAXTESTRUN; n++) {
        int64_t t = (int64_t)(mean - _testRuns[n]);
        stddiv += t * t;
    }
    stddiv = sqrt(stddiv / MAXTESTRUN);
    printf("] seconds average: %0.2lf relative standard deviation: %0.2lf%%\n",
           (double)mean / NSEC_PER_SEC, 100 * stddiv / mean);
}

- (void)startMeasuring
{
    _start = relative_nano_time();
}

- (void)stopMeasuring
{
    uint64_t stop = relative_nano_time();

    if (_start == 0)
        @throw [NSException exceptionWithName:@"startMeasuringNeverCalled"
                                       reason:@"test case failure"
                                     userInfo:nil];
    if (_testrun >= MAXTESTRUN) abort();
    _testRuns[_testrun] = stop - _start;
    _start = 0;
}


@end