Skip to content

Commit

Permalink
say: generate tests (exercism#885)
Browse files Browse the repository at this point in the history
Part of exercism#605.
Closes exercism#837
  • Loading branch information
Sean Perry authored and robphoenix committed Oct 10, 2017
1 parent e15f762 commit 7907379
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 40 deletions.
70 changes: 70 additions & 0 deletions exercises/say/.meta/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"fmt"
"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("say", &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
Comments []string
Cases []OneCase
}

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

func (c OneCase) ErrorExpected() bool {
switch value := c.Expected.(type) {
case float64: // you'd think int but no, JSON uses float for numbers
if value == -1 {
return true
}
case string:
return false
}

panic(fmt.Sprintf("Unexpected error value: %T => %v", c.Expected, c.Expected))
}

// Template to generate test cases.
var tmpl = `package say
{{.Header}}
var testCases = []struct {
description string
input int64
expected string
expectError bool
}{ {{range .J.Cases}}
{
description: {{printf "%q" .Description}},
input: {{printf "%v" .Input}},
{{if .ErrorExpected}}expectError: true,
{{else}}expected: {{printf "%q" .Expected}},
{{- end}}
},{{end}}
}
`
88 changes: 88 additions & 0 deletions exercises/say/cases_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package say

// Source: exercism/problem-specifications
// Commit: be403e1 say: Fix canonical-data.json formatting
// Problem Specifications Version: 1.0.0

var testCases = []struct {
description string
input int64
expected string
expectError bool
}{
{
description: "zero",
input: 0,
expected: "zero",
},
{
description: "one",
input: 1,
expected: "one",
},
{
description: "fourteen",
input: 14,
expected: "fourteen",
},
{
description: "twenty",
input: 20,
expected: "twenty",
},
{
description: "twenty-two",
input: 22,
expected: "twenty-two",
},
{
description: "one hundred",
input: 100,
expected: "one hundred",
},
{
description: "one hundred twenty-three",
input: 123,
expected: "one hundred twenty-three",
},
{
description: "one thousand",
input: 1000,
expected: "one thousand",
},
{
description: "one thousand two hundred thirty-four",
input: 1234,
expected: "one thousand two hundred thirty-four",
},
{
description: "one million",
input: 1000000,
expected: "one million",
},
{
description: "one million two thousand three hundred forty-five",
input: 1002345,
expected: "one million two thousand three hundred forty-five",
},
{
description: "one billion",
input: 1000000000,
expected: "one billion",
},
{
description: "a big number",
input: 987654321123,
expected: "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three",
},
{
description: "numbers below zero are out of range",
input: -1,
expectError: true,
},
{
description: "numbers above 999,999,999,999 are out of range",
input: 1000000000000,
expectError: true,
},
}
16 changes: 12 additions & 4 deletions exercises/say/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ var tens = []string{"ones", "ten", "twenty", "thirty", "forty",
var scale = []string{"thousand", "million", "billion",
"trillion", "quadrillion", "quintillion"}

func Say(n uint64) string {
func Say(n int64) (value string, ok bool) {
if n < 0 || n > 999999999999 {
return
}
return say(n), true
}

func say(n int64) string {
switch {
case n < 20:
return small[n]
Expand All @@ -23,18 +30,19 @@ func Say(n uint64) string {
h := small[n/100] + " hundred"
s := n % 100
if s > 0 {
h += " " + Say(s)
h += " " + say(s)
}
return h
}
sx := ""

if p := n % 1000; p > 0 {
sx = Say(p)
sx = say(p)
}
for i := 0; n >= 1000; i++ {
n /= 1000
if p := n % 1000; p > 0 {
ix := Say(p) + " " + scale[i]
ix := say(p) + " " + scale[i]
if sx > "" {
ix += " " + sx
}
Expand Down
54 changes: 18 additions & 36 deletions exercises/say/say_test.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,29 @@
package say

// The steps are interesting, but all that matters is the final exam.

import (
"math"
"testing"
)

var tests = []struct {
uint64
string
}{
{1, "one"},
{14, "fourteen"},
{20, "twenty"},
{22, "twenty-two"},
{100, "one hundred"},
{120, "one hundred twenty"},
{123, "one hundred twenty-three"},
{1000, "one thousand"},
{1234, "one thousand two hundred thirty-four"},
{1000000, "one million"},
{1000002, "one million two"},
{1002345, "one million two thousand three hundred forty-five"},
{1e9, "one billion"},
{987654321123, "nine hundred eighty-seven billion " +
"six hundred fifty-four million " +
"three hundred twenty-one thousand " +
"one hundred twenty-three"},
{0, "zero"},
{math.MaxUint64, "eighteen quintillion " +
"four hundred forty-six quadrillion " +
"seven hundred forty-four trillion " +
"seventy-three billion " +
"seven hundred nine million " +
"five hundred fifty-one thousand " +
"six hundred fifteen"},
func TestSay(t *testing.T) {
for _, tc := range testCases {
actual, ok := Say(tc.input)
if tc.expectError {
if ok {
t.Fatalf("FAIL: %s\nExpected error but received: %v", tc.description, actual)
}
} else if !ok {
t.Fatalf("FAIL: %s\nDid not expect an error", tc.description)
} else if actual != tc.expected {
t.Fatalf("FAIL: %s\nExpected: %v\nActual: %v", tc.description, tc.expected, actual)
}
t.Logf("PASS: %s", tc.description)
}
}

func TestSay(t *testing.T) {
for _, test := range tests {
if s := Say(test.uint64); s != test.string {
t.Errorf("Say(%d) = %q. Want %q.", test.uint64, s, test.string)
func BenchmarkSay(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testCases {
Say(tc.input)
}
}
}

0 comments on commit 7907379

Please sign in to comment.