//
//  MYOttoman_test.m
//  Ottoman
//
//  Created by Jens Alfke on 9/24/09.
//  Copyright 2009 Jens Alfke. All rights reserved.
//

#import "MYOttoman.h"
#import "MYVersionDictionary.h"

#import "Test.h"

static NSData* dataOf (NSString *str) {
    return [str dataUsingEncoding: NSUTF8StringEncoding];
}

/*
static NSString* stringOf (id data) {
    if (!data)
        return nil;
    CAssert([data isKindOfClass: [NSData class]], @"stringOf expected NSData, got %@", [data class]);
    NSString *str = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
    CAssert(str!=nil, @"Bad data (couldn't decode UTF-8): %@", data);
    return str;
}
*/

static void checkFile (NSString *path) {
    NSError *error;
    NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath: path error: &error];
    CAssert(fileInfo, @"Couldn't get info for %@: %@", path,error);
    CAssert([fileInfo fileSize] >= 512, @"Unexpected file size %lld", [fileInfo fileSize]);
    NSTimeInterval age = - [[fileInfo fileModificationDate] timeIntervalSinceNow];
    CAssert(age < 60.0, @"File %@ is too old: %.1lf sec", path,age);
}


TestCase(CreateMYOttoman) {
    MYOttoman *o = [[MYOttoman alloc] init];
    MYCurrentVersionDictionary *cur = o.currentVersion;
    CAssertEq(o.lastVersion,nil);
    
    [cur setObject: dataOf(@"first value") forKey: dataOf(@"first key")];
    [cur setObject: dataOf(@"second value") forKey: dataOf(@"second key")];
    [cur setObject: dataOf(@"third value") forKey: dataOf(@"third key")];
    [cur removeObjectForKey: dataOf(@"third key")];
    [cur removeObjectForKey: dataOf(@"bogus")];

    CAssertEq(cur.count, 2);
    CAssertEqual([cur objectForKey: dataOf(@"first key")], dataOf(@"first value"));
    CAssertEqual([cur objectForKey: dataOf(@"second key")], dataOf(@"second value"));
    CAssertEqual([cur objectForKey: dataOf(@"third key")], nil);

    NSError *error;
    if (![o saveAs: [NSURL fileURLWithPath: @"/tmp/myottomantest.ottoman"]
                          overwriteAllowed: YES error: &error])
        CAssert(NO, @"saveAs: failed: %@", error);
    checkFile(@"/tmp/myottomantest.ottoman");
    
    MYVersionDictionary *last = o.lastVersion;
    CAssert(last, @"lastVersion is nil after save");
    CAssertEq(last.generation,0);
    CAssertEqual([last objectForKey: dataOf(@"first key")], dataOf(@"first value"));
    CAssertEqual([last objectForKey: dataOf(@"second key")], dataOf(@"second value"));
    CAssertEqual([last objectForKey: dataOf(@"third key")], nil);
    
    [cur setObject: dataOf(@"fourth value") forKey: dataOf(@"fourth key")];
    [cur setObject: dataOf(@"new first value") forKey: dataOf(@"first key")];
    [cur removeObjectForKey: dataOf(@"second key")];
    CAssertEq(cur.count, 2);
    CAssertEqual([cur objectForKey: dataOf(@"first key")], dataOf(@"new first value"));
    CAssertEqual([cur objectForKey: dataOf(@"second key")], nil);
    CAssertEqual([cur objectForKey: dataOf(@"fourth key")], dataOf(@"fourth value"));

    if (![o save: &error])
        CAssert(NO, @"save: failed: %@", error);
 
    CAssertEqual([last objectForKey: dataOf(@"first key")], dataOf(@"first value"));
    CAssertEqual([last objectForKey: dataOf(@"second key")], dataOf(@"second value"));
    CAssertEqual([last objectForKey: dataOf(@"third key")], nil);

    last = o.lastVersion;
    CAssertEq(last.generation,1);
    CAssertEqual([last objectForKey: dataOf(@"first key")], dataOf(@"new first value"));
    CAssertEqual([last objectForKey: dataOf(@"second key")], nil);
    CAssertEqual([last objectForKey: dataOf(@"third key")], nil);
    CAssertEqual([last objectForKey: dataOf(@"fourth key")], dataOf(@"fourth value"));

    [o close];
    [o release];
    
    o = [[MYOttoman alloc] initWithURL: [NSURL fileURLWithPath: @"/tmp/myottomantest.ottoman"]
                              writeable: NO error: &error];
    CAssert(o, @"Failed to re-open Ottoman: %@", error);
    CAssertEq(o.currentVersion, nil);
    last = o.lastVersion;
    CAssertEq(last.generation,1);
    CAssertEqual([last objectForKey: dataOf(@"first key")], dataOf(@"new first value"));
    CAssertEqual([last objectForKey: dataOf(@"second key")], nil);
    CAssertEqual([last objectForKey: dataOf(@"third key")], nil);
    CAssertEqual([last objectForKey: dataOf(@"fourth key")], dataOf(@"fourth value"));
    
    MYVersionDictionary *prev = last.previousVersion;
    CAssert(prev!=nil);
    CAssertEq(prev.generation,0);
    CAssertEq(prev.previousVersion,nil);
    CAssertEqual([prev objectForKey: dataOf(@"first key")], dataOf(@"first value"));
    CAssertEqual([prev objectForKey: dataOf(@"second key")], dataOf(@"second value"));
    CAssertEqual([prev objectForKey: dataOf(@"third key")], nil);
        
    [o close];
    [o release];
}


int main(int argc, const char**argv) {
    const char* testArgs[2] = {"", "Test_All"};
    RunTestCases(2,testArgs);
    return 0;
}
