//
//  UnitsTest.m
//  MealBuilder
//
//  Created by Phil Horowitz on 2/13/13.
//  Copyright (c) 2013 Phil Horowitz. All rights reserved.
//

#import "UnitsTest.h"
#import "Measurements.h"

@interface UnitsTest()
@property (strong, nonatomic) Milliliter *ml;
@end

@implementation UnitsTest
-(void) setUp{
    self.ml = [[Milliliter alloc] init];
}
-(void)tearDown{
    // nothing here yet
}

-(void)testIsEqual{
    Unit *ml1 = [[Milliliter alloc] initWithAmount:2973];
    Unit *ml2 = [ml1 copy];
    
    STAssertTrue([ml1 isEqual:ml2], @"isEqual should return true if the type is the same and the values are the same");
    
    Unit *gram = [[Gram alloc] initWithAmount:2973];
    STAssertFalse([ml1 isEqual:gram], @"isEqual should always return false between 2 incompatible measurements");
    
    Unit *floz = [[FluidOunce alloc] initFromCompatibleUnit:ml1];
    STAssertTrue([floz isEqual:ml1], @"Units that are equal once converted should return true");
    STAssertTrue([ml1 isEqual:floz], @"Units that are equal once converted should return true");
}

#pragma mark Name Tests
-(void) testMLName{
    NSString *mlName = self.ml.unitName;
    STAssertTrue([mlName isEqualToString: @"ml"], @"Milliliter's name should be ml");
}

#pragma mark Initialization Tests
-(void) testMLInitializingFromValue{
    Milliliter *ml = [[Milliliter alloc ]initWithAmount: 0];
    STAssertTrue(ml.amount == 0, @"Milliliter isn't properly initializing to 0");
}

-(void) testMLInitializingFromValue2{
    Milliliter *ml = [[Milliliter alloc ]initWithAmount: 100];
    STAssertTrue(ml.amount == 100, @"Milliliter isn't properly initializing to 0");
}

-(void) testMLInitializingFromBaseValue{
    Unit *ml = [[Milliliter alloc] initWithAmount:0];
    STAssertTrue(ml.amount == 0, @"Milliliter isn't getting properly initialized with a base value of 0");
}
-(void) testMLInitializingFromBaseValue2{
    Unit *ml = [[Milliliter alloc] initWithAmount:100];
    STAssertTrue(ml.amount == 100, @"Milliliter isn't getting properly initialized with a base value of 100");
}

#pragma mark Conversion Tests
-(void)testFromCompatibleUnitML{
    Unit *baseML = [[Milliliter alloc] initWithAmount:10];
    Unit *ml = [[Milliliter alloc] initFromCompatibleUnit:baseML];
    
    STAssertTrue(baseML.amount == ml.amount, @"fromBaseUnit in ML should set the same value when called on a base unit");
    
    Unit *baseFLOZ = [[FluidOunce alloc] initWithAmount:20];
    ml = [[Milliliter alloc] initFromCompatibleUnit:baseFLOZ];
    STAssertNotNil(ml, @"Initializing a milliliter from a fluid ounce should be valid");
    STAssertEquals(ml.amount, [baseFLOZ toBaseUnit].amount, @"fromCompatibleUnit should convert the unit passed in");
    
    Unit* baseGram = [[Gram alloc] initWithAmount:13];
    ml = [[Milliliter alloc] initFromCompatibleUnit:baseGram];
    STAssertNil(ml, @"Initializing a milliliter from a gram should not be valid");
}
-(void)testFromCompatibleUnitGram{
    Unit *baseGram = [[Gram alloc] initWithAmount:10];
    Unit *gram = [[Gram alloc] initFromCompatibleUnit:baseGram];
    
    STAssertTrue(baseGram.amount == gram.amount, @"fromBaseUnit in Gram should set the same value when called on a base unit");
    
    STAssertNil([[Gram alloc] initFromCompatibleUnit:[[FluidOunce alloc] init] ], @"Converting to gram from a different type should be nil");
}

-(void)testFromCompatibleUnitFlOz{
    float mlAmount = 240;
    Unit* ml = [[Milliliter alloc] initWithAmount:mlAmount];
    Unit* testfloz = [[FluidOunce alloc]initFromCompatibleUnit:ml];
    
    STAssertNotNil(testfloz, @"Converting from ml should be valid");
    STAssertEqualsWithAccuracy([testfloz toBaseUnit].amount, mlAmount, 0.1f, @"Converting from ML should yield the proper amount");
    
    Unit* gram = [[Gram alloc] initWithAmount:20];
    testfloz = [[FluidOunce alloc] initFromCompatibleUnit:gram];
    STAssertNil(testfloz, @"Converting from a different unit should be invalid");
}

-(void)testGramToML{
    Unit* gram = [[Gram alloc] initWithAmount:10];
    Unit* ml = [[Milliliter alloc]initFromCompatibleUnit:gram];
    
    STAssertFalse(gram.amount == ml.amount, @"Units with different bases should not convert");
}

-(void)testMLToGram{
    Unit* ml = [[Milliliter alloc] initWithAmount:10];
    Unit* gram = [[Gram alloc]initFromCompatibleUnit:ml];
    
    STAssertTrue(gram == nil, @"Units with different bases should not convert");
}

-(void)testGramToFlOz{
    Unit* gram = [[Gram alloc] initWithAmount:100];
    Unit* floz = [[FluidOunce alloc]initFromCompatibleUnit:gram];
    
    STAssertTrue(floz == nil, @"Conversion from Gram to Fluid Ounce should be nil");
}


#pragma mark Addition Tests
-(void) testAddToML{
    float mlValue = 10;
    Unit *testML = [[Milliliter alloc] initWithAmount:mlValue];
    [testML addCompatibleUnit:[[Milliliter alloc] initWithAmount:mlValue]];
    
    STAssertEqualsWithAccuracy(testML.amount, mlValue*2, 0.1, @"addCompatibleUnit should add to the given amount");
    
    testML.amount = mlValue;
    [testML addCompatibleUnit:testML];
    
    STAssertEqualsWithAccuracy(mlValue *2, testML.amount, 0.1f, @"Unit adding to itself should be valid");
    
    testML.amount = mlValue;
    [testML addCompatibleUnit:[[Gram alloc] initWithAmount:10]];
    STAssertEqualsWithAccuracy(mlValue, testML.amount, 0.1f, @"Adding from non-compatible base type should not affect the base unit");
    
    testML.amount = mlValue;
    Unit *floz = [[FluidOunce alloc] initWithAmount:275];
    float expectedAmont = mlValue + [floz toBaseUnit].amount;
    [testML addCompatibleUnit:floz];
    STAssertEqualsWithAccuracy(testML.amount, expectedAmont, 0.1f, @"Adding a compatible unit should accurately convert and add the given amount");
}

-(void)testAddToFlOz{
    float flValue = 20;
    Unit *flTest = [[FluidOunce alloc] initWithAmount:flValue];
    [flTest addCompatibleUnit:[[FluidOunce alloc] initWithAmount:flValue]];
    STAssertEqualsWithAccuracy(flValue * 2, flTest.amount, 0.1f, @"addCompatibleUint should add to the given amount");
    
    flTest.amount = flValue;
    [flTest addCompatibleUnit:[[Gram alloc] initWithAmount:flValue]];
    STAssertEqualsWithAccuracy(flValue, flTest.amount, 0.1f, @"Adding from non-compatible base type should not affect the base unit");
    
    flTest.amount = flValue;
    Unit* ml = [[Milliliter alloc] initWithAmount:1576];
    float expectedAmount = [flTest toBaseUnit].amount + ml.amount;
    [flTest addCompatibleUnit:ml];
    STAssertEqualsWithAccuracy(expectedAmount, [flTest toBaseUnit].amount, 0.1f, @"Adding a compatible unit should accurately convert and add the given amount");
}

-(void)testAddToGram{
    float gValue = 10;
    Unit *gramTest = [[Gram alloc] initWithAmount:gValue];
    [gramTest addCompatibleUnit:gramTest];
    STAssertEqualsWithAccuracy(gValue * 2, gramTest.amount, 0.1f, @"addCompatibleUnit should add to the given amount");
    
    gramTest.amount= gValue;
    Unit *ml = [[Milliliter alloc] initWithAmount:20];
    [gramTest addCompatibleUnit:ml];
    
    STAssertEqualsWithAccuracy(gramTest.amount, gValue, 0.1, @"Adding from non-compatible type should not affect the base unit");
    
}

@end
