Skip to content

Commit

Permalink
grains: add generator
Browse files Browse the repository at this point in the history
Add .meta/gen.go to generate cases_test.go.
Make use of zero-value of expectError bool.

Update test program to use generated test case array.
The test case value for the 'Total()' is retained in TestTotal()
since there wasn't an array of cases in the canonical-data.json
for the 'total' property, and there is only one valid return value.

For exercism#605.
  • Loading branch information
leenipper committed Nov 15, 2017
1 parent 999244e commit faac054
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 20 deletions.
103 changes: 103 additions & 0 deletions exercises/grains/.meta/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package main

import (
"encoding/json"
"log"
"strings"
"text/template"

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

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

// The JSON structure we expect to be able to unmarshal into
type js struct {
Groups []testGroup `json:"Cases"`
}

type testGroup struct {
Description string
Cases []json.RawMessage `property:"RAW"`
SquareCases []SquareCase `property:"square"`
// Note: canonical-data.json has a element of "cases"
// which includes a test for property 'total', but it is ignored here,
// since "expected" is a single known value.
}

type SquareCase struct {
Description string
Input int
Expected interface{}
}

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

func (c SquareCase) Answer() uint64 {
_, answer := determineExpected(c.Expected)
return answer
}

func (c SquareCase) EditedDescription() string {
// Go doesn't raise exceptions, so replace the wording in .Description.
return strings.Replace(c.Description, "raises an exception", "returns an error", 1)
}

// determineExpected examines an .Expected interface{} object and determines
// whether a test case is valid(bool) and has an answer or expects an error.
// returning valid and answer.
func determineExpected(expected interface{}) (bool, uint64) {
ans, ok := expected.(float64)
if ok {
if ans == float64(-1) {
return false, 0
}
return ok, uint64(ans)
}
return false, 0
}

func (groups testGroup) GroupShortName() string {
return strings.ToLower(strings.Fields(groups.Description)[0])
}

var tmpl = `package grains
{{.Header}}
{{range .J.Groups}}
{{- if .SquareCases }}
// {{ .Description }}
var squareTests = []struct {
description string
input int
expectedVal uint64
expectError bool
}{
{{- range .SquareCases}}
{
description: "{{.EditedDescription}}",
input: {{.Input}},
{{- if .Valid}}
expectedVal: {{.Answer}},
{{- else}}
expectError: true,
{{- end}}
},
{{- end }}
}
{{- end }}
{{end}}
`
64 changes: 64 additions & 0 deletions exercises/grains/cases_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package grains

// Source: exercism/problem-specifications
// Commit: d4554e6 grains: fix a typo in comments of canonical data
// Problem Specifications Version: 1.0.0

// returns the number of grains on the square
var squareTests = []struct {
description string
input int
expectedVal uint64
expectError bool
}{
{
description: "1",
input: 1,
expectedVal: 1,
},
{
description: "2",
input: 2,
expectedVal: 2,
},
{
description: "3",
input: 3,
expectedVal: 4,
},
{
description: "4",
input: 4,
expectedVal: 8,
},
{
description: "16",
input: 16,
expectedVal: 32768,
},
{
description: "32",
input: 32,
expectedVal: 2147483648,
},
{
description: "64",
input: 64,
expectedVal: 9223372036854775808,
},
{
description: "square 0 returns an error",
input: 0,
expectError: true,
},
{
description: "negative square returns an error",
input: -1,
expectError: true,
},
{
description: "square greater than 64 returns an error",
input: 65,
expectError: true,
},
}
24 changes: 4 additions & 20 deletions exercises/grains/grains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,25 @@ import (
"testing"
)

var squareTests = []struct {
input int
expectedVal uint64
expectError bool
}{
{1, 1, false},
{2, 2, false},
{3, 4, false},
{4, 8, false},
{16, 32768, false},
{32, 2147483648, false},
{64, 9223372036854775808, false},
{65, 0, true},
{0, 0, true},
{-1, 0, true},
}

func TestSquare(t *testing.T) {
for _, test := range squareTests {
actualVal, actualErr := Square(test.input)

// check actualVal only if no error expected
if !test.expectError && actualVal != test.expectedVal {
t.Errorf("Square(%d) expected %d, Actual %d", test.input, test.expectedVal, actualVal)
t.Fatalf("FAIL: %s\nSquare(%d) expected %d, Actual %d", test.description, test.input, test.expectedVal, actualVal)
}

// if we expect an error and there isn't one
if test.expectError && actualErr == nil {
t.Errorf("Square(%d) expected an error, but error is nil", test.input)
t.Fatalf("FAIL: %s\nSquare(%d) expected an error, but error is nil", test.description, test.input)
}
// if we don't expect an error and there is one
if !test.expectError && actualErr != nil {
var _ error = actualErr
t.Errorf("Square(%d) expected no error, but error is: %s", test.input, actualErr)
t.Fatalf("FAIL: %s\nSquare(%d) expected no error, but error is: %s", test.description, test.input, actualErr)
}
t.Logf("PASS: %s", test.description)
}
}

Expand Down

0 comments on commit faac054

Please sign in to comment.