Skip to content

perfect-numbers: create test case generator #952

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions exercises/perfect-numbers/.meta/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"log"
"text/template"

"../../../gen"
)

func main() {
t, err := template.New("").Parse(tmpl)
if err != nil {
log.Fatal(err)
}
var j js
if err := gen.Gen("perfect-numbers", &j, t); err != nil {
log.Fatal(err)
}
}

// The JSON structure we expect to be able to unmarshal into
type js struct {
Exercise string
Version string
Cases []struct {
Description string
Cases []oneCase
}
}

// Test cases
type oneCase struct {
Description string
Property string
Input int64
Expected interface{}
}

func (c oneCase) Valid() bool {
valid, _ := determineExpected(c.Expected)
return valid
}

func (c oneCase) ExpectedClassification() string {
_, e := determineExpected(c.Expected)
switch e {
case "perfect":
return "ClassificationPerfect"
case "abundant":
return "ClassificationAbundant"
case "deficient":
return "ClassificationDeficient"
}
return e
}

// determineExpected examines an .Expected interface{} object and determines
// whether a test case is valid(bool) and has a classification or expects an error,
// returning valid and classification.
func determineExpected(expected interface{}) (bool, string) {
exp, ok := expected.(string)
if ok {
return ok, exp
}
return false, ""
}

// Template to generate test cases.
var tmpl = `package perfect

{{.Header}}

var classificationTestCases = []struct {
description string
input int64
ok bool
expected Classification
}{ {{range .J.Cases}} {{range .Cases}}
{
description: "{{.Description}}",
input: {{.Input}},
{{if .Valid}} ok: true,
expected: {{.ExpectedClassification}},
{{- else}} ok: false,
{{- end}}
},{{end}}{{end}}
}
`
89 changes: 89 additions & 0 deletions exercises/perfect-numbers/cases_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package perfect

// Source: exercism/problem-specifications
// Commit: 924bb7a perfect-numbers: fix misleading test description
// Problem Specifications Version: 1.0.1

var classificationTestCases = []struct {
description string
input int64
ok bool
expected Classification
}{
{
description: "Smallest perfect number is classified correctly",
input: 6,
ok: true,
expected: ClassificationPerfect,
},
{
description: "Medium perfect number is classified correctly",
input: 28,
ok: true,
expected: ClassificationPerfect,
},
{
description: "Large perfect number is classified correctly",
input: 33550336,
ok: true,
expected: ClassificationPerfect,
},
{
description: "Smallest abundant number is classified correctly",
input: 12,
ok: true,
expected: ClassificationAbundant,
},
{
description: "Medium abundant number is classified correctly",
input: 30,
ok: true,
expected: ClassificationAbundant,
},
{
description: "Large abundant number is classified correctly",
input: 33550335,
ok: true,
expected: ClassificationAbundant,
},
{
description: "Smallest prime deficient number is classified correctly",
input: 2,
ok: true,
expected: ClassificationDeficient,
},
{
description: "Smallest non-prime deficient number is classified correctly",
input: 4,
ok: true,
expected: ClassificationDeficient,
},
{
description: "Medium deficient number is classified correctly",
input: 32,
ok: true,
expected: ClassificationDeficient,
},
{
description: "Large deficient number is classified correctly",
input: 33550337,
ok: true,
expected: ClassificationDeficient,
},
{
description: "Edge case (no factors other than itself) is classified correctly",
input: 1,
ok: true,
expected: ClassificationDeficient,
},
{
description: "Zero is rejected (not a natural number)",
input: 0,
ok: false,
},
{
description: "Negative integer is rejected (not a natural number)",
input: -1,
ok: false,
},
}
8 changes: 4 additions & 4 deletions exercises/perfect-numbers/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ var (
)

// Classify finds the category of given natural number
func Classify(n uint64) (Classification, error) {
if n == 0 {
func Classify(n int64) (Classification, error) {
if n <= 0 {
return "", ErrOnlyPositive
}
var sum uint64
for i := uint64(1); i < n; i++ {
var sum int64
for i := int64(1); i < n; i++ {
if n%i == 0 {
if sum = sum + i; sum > n {
return ClassificationAbundant, nil
Expand Down
31 changes: 13 additions & 18 deletions exercises/perfect-numbers/perfect_numbers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,27 @@ import "testing"

var _ error = ErrOnlyPositive

var classificationTestCases = []struct {
input uint64
expected Classification
}{
{1, ClassificationDeficient},
{13, ClassificationDeficient},
{12, ClassificationAbundant},
{6, ClassificationPerfect},
{28, ClassificationPerfect},
{496, ClassificationPerfect},
{8128, ClassificationPerfect},
}

func TestGivesPositiveRequiredError(t *testing.T) {
if _, err := Classify(0); err != ErrOnlyPositive {
t.Errorf("Expected error %q but got %q", ErrOnlyPositive, err)
t.Fatalf("FAIL GivesPositiveRequiredError Expected error %q but got %q", ErrOnlyPositive, err)
}
t.Logf("PASS GivesPositiveRequiredError")
}

func TestClassifiesCorrectly(t *testing.T) {
for _, c := range classificationTestCases {
if cat, err := Classify(c.input); err != nil {
t.Errorf("%d: Expected no error but got %s", c.input, err)
} else if cat != c.expected {
t.Errorf("%d: Expected %q, got %q", c.input, c.expected, cat)
cat, err := Classify(c.input)
switch {
case err != nil:
if c.ok {
t.Fatalf("FAIL %s\nClassify(%d)\nExpected no error but got error %q", c.description, c.input, err)
}
case !c.ok:
t.Fatalf("FAIL %s\nClassify(%d)\nExpected error but got %q", c.description, c.input, cat)
case cat != c.expected:
t.Fatalf("FAIL %s\nClassify(%d)\nExpected %q, got %q", c.description, c.input, c.expected, cat)
}
t.Logf("PASS %s", c.description)
}
}

Expand Down