diff --git a/assessment_test.go b/assessment_test.go index df18a0d..14f75f9 100644 --- a/assessment_test.go +++ b/assessment_test.go @@ -1,11 +1,73 @@ package phass import ( + "fmt" "math" + "strings" "testing" "time" ) +func TestPersonMeasurerInterface(t *testing.T) { + cases := []struct { + name string + dob string + gender int + err error + }{ + { + name: "Person 1", + dob: "1978-Dec-15", + gender: Male, + err: nil, + }, + { + name: "Person 2", + dob: "1988-Mar-08", + gender: Female, + err: nil, + }, + } + + for _, data := range cases { + p, err := NewPerson(data.name, data.dob, data.gender) + if err != data.err { + t.Error("This is a valid person") + } + + if p.GetName() != "Person" { + t.Error("Wrong measurement name") + } + + rs, err := p.Result() + if err != nil { + t.Error("This is a valid result") + } else if len(rs) != 4 { + t.Error("There should be 4 information about person") + } + for index, item := range rs { + switch index { + case 0: + if !strings.Contains(item, p.FullName) { + t.Error("Full name should be present") + } + case 1: + if !strings.Contains(item, p.genderRepr()) { + t.Error("Gender representation should be present") + } + case 2: + if !strings.Contains(item, fmt.Sprintf("%.0f", p.Age())) { + t.Error("Age in years should be present") + } + case 3: + if !strings.Contains(item, fmt.Sprintf("%.1f", p.AgeInMonths())) { + t.Error("Age in months should be present") + } + } + } + } +} + func TestPersonBirth(t *testing.T) { _, err := NewPerson("Someone", "1900-Dec-40", Male) if err == nil { diff --git a/bodyfat_test.go b/bodyfat_test.go index ecc3893..feb5326 100644 --- a/bodyfat_test.go +++ b/bodyfat_test.go @@ -2,7 +2,6 @@ package phass import ( "math" - "strings" "testing" ) @@ -34,7 +33,7 @@ func TestBodyFatCompositionValidation(t *testing.T) { map[int]float64{SKFTriceps: 10.5, SKFSuprailiac: 26.9, SKFThigh: 21.2}, "Too young", 0.0, - "Valid for age", + ErrInvalidAge.Error(), ), newCaseBodyFat( female, @@ -42,7 +41,7 @@ func TestBodyFatCompositionValidation(t *testing.T) { map[int]float64{SKFTriceps: 10.5, SKFSuprailiac: 26.9, SKFThigh: 21.2}, "Too old", 0.0, - "Valid for age", + ErrInvalidAge.Error(), ), newCaseBodyFat( male, @@ -50,7 +49,7 @@ func TestBodyFatCompositionValidation(t *testing.T) { map[int]float64{SKFTriceps: 10.5, SKFSuprailiac: 26.9, SKFThigh: 21.2}, "Wrong gender", 0.0, - "Valid for gender", + ErrInvalidGender.Error(), ), newCaseBodyFat( female, @@ -58,7 +57,7 @@ func TestBodyFatCompositionValidation(t *testing.T) { map[int]float64{SKFTriceps: 10.5}, "Without skinfolds", 0.0, - "Missing skinfold", + "Missing skinfold suprailiac", ), newCaseBodyFat( female, @@ -74,7 +73,7 @@ func TestBodyFatCompositionValidation(t *testing.T) { bc := newEquation(data.person, data.assessment, data.skinfold) if calc, err := bc.Calc(); data.err != "" && err == nil { t.Errorf("Case _%s_ failed, should show a validation error", data.name) - } else if data.err != "" && !strings.Contains(err.Error(), data.err) { + } else if data.err != "" && err.Error() != data.err { t.Errorf("Case _%s_ failed, should show proper error message", data.name) } else if data.calc > 0.0 && !floatEqual(calc, data.calc, 0.009) { t.Errorf("Case _%s_ failed, should have value %.4f, instead got %.4f", data.name, data.calc, calc) diff --git a/common.go b/common.go index d3f55bd..55d30c5 100644 --- a/common.go +++ b/common.go @@ -1,6 +1,8 @@ package phass -import "fmt" +import ( + "errors" +) /** * Equation @@ -99,6 +101,15 @@ type Equationer interface { * Validation */ +// Validation error messages. +var ( + ErrMissingGender = errors.New("Missing gender") + ErrInvalidGender = errors.New("Invalid gender") + ErrMissingAge = errors.New("Missing age") + ErrInvalidAge = errors.New("Invalid age") + ErrMissingMeasure = errors.New("Missing measure") +) + // ValidateGender returns a Validator function, that ensure gender is equal to // the one expected. func ValidateGender(expect int) Validator { @@ -110,9 +121,9 @@ func ValidateGender(expect int) Validator { // validateGender ensure that gender is set and matches the expected value. func validateGender(expect int, e *Equation) (bool, error) { if g, ok := e.In("gender"); !ok { - return false, fmt.Errorf("Missing gender") + return false, ErrMissingGender } else if int(g) != expect { - return false, fmt.Errorf("Valid for gender %d", expect) + return false, ErrInvalidGender } return true, nil } @@ -128,9 +139,9 @@ func ValidateAge(lower, upper float64) Validator { // validateAge ensure that age is set and is between limits. func validateAge(lower, upper float64, e *Equation) (bool, error) { if age, ok := e.In("age"); !ok { - return false, fmt.Errorf("Missing age measure") + return false, ErrMissingAge } else if age < lower || age > upper { - return false, fmt.Errorf("Valid for ages between %.0f and %.0f", lower, upper) + return false, ErrInvalidAge } return true, nil } @@ -147,7 +158,7 @@ func ValidateMeasures(expect []string) Validator { func validateMeasures(expect []string, e *Equation) (bool, error) { for _, k := range expect { if _, ok := e.In(k); !ok { - return false, fmt.Errorf("Missing %s measure", k) + return false, ErrMissingMeasure } } return true, nil diff --git a/common_test.go b/common_test.go index d96374c..2fb3d45 100644 --- a/common_test.go +++ b/common_test.go @@ -1,153 +1,230 @@ package phass import ( - "fmt" "math" - "strings" "testing" ) func TestEquationValidation(t *testing.T) { - cases := []caseCommon{ - {in: map[string]float64{}, ok: false, err: "Missing measure"}, - {in: map[string]float64{"age": 18.0}, ok: false, err: "Missing measure"}, - {in: map[string]float64{"sskf": 112.1}, ok: false, err: "Missing measure"}, - {in: map[string]float64{"age": 17.9, "sskf": 112.1}, ok: false, err: "Equation valid for age"}, + cases := []struct { + in InParams + ok bool + err error + }{ + { + in: map[string]float64{}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 18.0}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"sskf": 112.1}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 17.9, "sskf": 112.1}, + ok: false, + err: ErrInvalidAge, + }, + { + in: map[string]float64{"age": 20, "sskf": 109.2}, + ok: true, + err: nil, + }, } - for _, data := range cases { eq := NewEquation(data.in, conf) if v, err := eq.Validate(); v != data.ok { - t.Error("Should get an error.") - } else if !strings.Contains(err.Error(), data.err) { - t.Error("Should get proper error message.") + t.Error("Should get an error") + } else if err != data.err { + t.Error("Should get proper error message") } - if v, err := eq.Calc(); v > 0.0 { - t.Error("Value should be 0") - } else if !strings.Contains(err.Error(), data.err) { - t.Error("Should get proper error message.") + // NOTE: this checks if calc returns 0 when an error occurs. + if !data.ok { + if v, err := eq.Calc(); v > 0.0 { + t.Error("Value should be 0") + } else if err != data.err { + t.Error("Should get proper error message.") + } } } - - eq := NewEquation(map[string]float64{"age": 20, "sskf": 109.2}, conf) - if v, err := eq.Validate(); !v { - t.Errorf("Should be valid, instead get: %s", err) - } - if v, err := eq.Calc(); v <= 0.0 && err != nil { - t.Errorf("Should get value greater that 0, instead get error %s", err) - } - } -func TestEquationRetrieveIn(t *testing.T) { +func TestEquationRetrieveInputParameters(t *testing.T) { in := map[string]float64{ "age": 18.8, "sskf": 210.1, } eq := NewEquation(in, conf) - for k, v := range in { - sv, ok := eq.In(k) - if !ok { - t.Errorf("Key %s should be defined.", k) - } - if v != sv { - t.Errorf("Key %s should have value %.2f.", k, v) + if sv, ok := eq.In(k); !ok { + t.Errorf("Key %s should be defined", k) + } else if v != sv { + t.Errorf("Key %s should have value %.2f", k, v) } } - - _, ok := eq.In("iDoNotExist") - if ok { + if _, ok := eq.In("iDoNotExist"); ok { t.Error("Key should no be available") } } +func TestGenderValidator(t *testing.T) { + cases := []struct { + in InParams + ok bool + err error + }{ + { + in: map[string]float64{}, + ok: false, + err: ErrMissingGender, + }, + { + in: map[string]float64{"gender": float64(Male)}, + ok: false, + err: ErrInvalidGender, + }, + { + in: map[string]float64{"gender": float64(Female)}, + ok: true, + err: nil, + }, + } + validator := ValidateGender(Female) + for _, data := range cases { + eq := NewEquation(data.in, conf).(*Equation) + if ok, err := validator(eq); ok != data.ok { + t.Error("Should receive a proper boolean") + } else if err != data.err { + t.Error("Should show proper error message") + } + } +} + func TestAgeValidator(t *testing.T) { - cases := []caseCommon{ + cases := []struct { + in InParams + ok bool + err error + }{ { in: map[string]float64{}, ok: false, - err: "Missing age", + err: ErrMissingAge, }, { in: map[string]float64{"age": 9}, ok: false, - err: "Valid for ages", + err: ErrInvalidAge, }, { in: map[string]float64{"age": 21}, ok: false, - err: "Valid for ages", + err: ErrInvalidAge, + }, + { + in: map[string]float64{"age": 15}, + ok: true, + err: nil, }, } - validator := ValidateAge(10, 20) for _, data := range cases { eq := NewEquation(data.in, conf).(*Equation) if ok, err := validator(eq); ok != data.ok { t.Error("Should receive a proper boolean") - } else if !strings.Contains(err.Error(), data.err) { + } else if err != data.err { t.Error("Should show proper error message") } } - - eq := NewEquation(map[string]float64{"age": 15}, conf).(*Equation) - if ok, err := validator(eq); !ok { - t.Error("Should receive proper boolean") - } else if err != nil { - t.Error("Should not get an error") - } } func TestMeasureValidator(t *testing.T) { - cases := []caseCommon{} + cases := []struct { + in InParams + ok bool + err error + }{ + { + in: map[string]float64{}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 10}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 10, "weight": 68}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 10, "height": 168}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"weight": 68, "height": 168}, + ok: false, + err: ErrMissingMeasure, + }, + { + in: map[string]float64{"age": 10, "weight": 68, "height": 168}, + ok: true, + err: nil, + }, + } validator := ValidateMeasures([]string{"age", "weight", "height"}) for _, data := range cases { eq := NewEquation(data.in, conf).(*Equation) if ok, err := validator(eq); ok != data.ok { t.Error("Should receive proper boolean") - } else if strings.Contains(err.Error(), data.err) { + } else if err != data.err { t.Error("Should show proper error message.") } } } -type caseCommon struct { - in InParams - ok bool - err string -} - var conf = NewEquationConf( "Testing", func(i interface{}) InParams { return map[string]float64{} }, []Validator{ + // ensure age and sskf measures are set func(e *Equation) (bool, error) { keys := []string{"age", "sskf"} for _, k := range keys { if _, ok := e.In(k); !ok { - return false, fmt.Errorf("Missing measure %s", k) + return false, ErrMissingMeasure } } return true, nil }, + // ensure age is between 18 and 64 years func(e *Equation) (bool, error) { v, ok := e.In("age") if !ok { - return false, fmt.Errorf("Missing measure age") + return false, ErrMissingAge } lower, upper := 18.0, 64.0 if v < lower || v >= upper { - return false, fmt.Errorf("Equation valid for age %.0f up to %.0f", lower, upper) + return false, ErrInvalidAge } return true, nil }, }, + // equation that calculates body density and convert into body fat. func(e *Equation) float64 { age, _ := e.In("age") sskf, _ := e.In("sskf")