summaryrefslogtreecommitdiff
path: root/go/grade-school/grade_school_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/grade-school/grade_school_test.go')
-rw-r--r--go/grade-school/grade_school_test.go173
1 files changed, 173 insertions, 0 deletions
diff --git a/go/grade-school/grade_school_test.go b/go/grade-school/grade_school_test.go
new file mode 100644
index 0000000..a827baf
--- /dev/null
+++ b/go/grade-school/grade_school_test.go
@@ -0,0 +1,173 @@
+// API:
+//
+// type Grade struct {
+// int, []string
+// }
+//
+// type School
+// func New() *School
+// func (s *School) Add(string, int)
+// func (s *School) Grade(int) []string
+// func (s *School) Enrollment() []Grade
+
+package school
+
+import (
+ "fmt"
+ "math/rand"
+ "strconv"
+ "testing"
+)
+
+func TestNewSchoolIsEmpty(t *testing.T) {
+ if len(New().Enrollment()) != 0 {
+ t.Error("New school not empty")
+ }
+}
+
+func list(e []Grade) (s string) {
+ for _, l := range e {
+ s += fmt.Sprintln(l)
+ }
+ return s
+}
+
+func TestAddStudent(t *testing.T) {
+ exp := list([]Grade{{2, []string{"Aimee"}}})
+ s := New()
+ s.Add("Aimee", 2)
+ got := list(s.Enrollment())
+ if got != exp {
+ t.Errorf(`Add Aimee level 2, got
+%sexpected:
+%s`, got, exp)
+ }
+}
+
+func TestAddMoreSameGrade(t *testing.T) {
+ exp := list([]Grade{{2, []string{"Blair James Paul"}}})
+ s := New()
+ s.Add("Blair", 2)
+ s.Add("James", 2)
+ s.Add("Paul", 2)
+ got := list(s.Enrollment())
+ if got != exp {
+ t.Errorf(`Add more same grade, got
+%sexpected:
+%s`, got, exp)
+ }
+}
+
+func TestAddDifferentGrades(t *testing.T) {
+ exp := list([]Grade{
+ {3, []string{"Chelsea"}},
+ {7, []string{"Logan"}},
+ })
+ s := New()
+ s.Add("Chelsea", 3)
+ s.Add("Logan", 7)
+ got := list(s.Enrollment())
+ if got != exp {
+ t.Errorf(`Add different grades, got
+%sexpected:
+%s`, got, exp)
+ }
+}
+
+func TestGetGrade(t *testing.T) {
+ exp := []string{"Bradley", "Franklin"}
+ s := New()
+ s.Add("Bradley", 5)
+ s.Add("Franklin", 5)
+ s.Add("Jeff", 1)
+ got := s.Grade(5)
+ if len(got) == len(exp) {
+ if got[0] == exp[0] && got[1] == exp[1] ||
+ got[0] == exp[1] && got[1] == exp[0] { // accept out of order
+ return
+ }
+ }
+ t.Errorf(`Get grade, got
+%v
+expected
+%v`, got, exp)
+}
+
+func TestNonExistantGrade(t *testing.T) {
+ s := New()
+ got := s.Grade(1)
+ if len(got) != 0 {
+ t.Errorf(`Get non-existant grade, got
+%v
+expected
+[]`, got)
+ }
+}
+
+func TestSortedEnrollment(t *testing.T) {
+ exp := list([]Grade{
+ {3, []string{"Kyle"}},
+ {4, []string{"Christopher Jennifer"}},
+ {6, []string{"Kareem"}},
+ })
+ s := New()
+ s.Add("Jennifer", 4)
+ s.Add("Kareem", 6)
+ s.Add("Christopher", 4)
+ s.Add("Kyle", 3)
+ got := list(s.Enrollment())
+ if got != exp {
+ t.Errorf(`Sorted enrollment, got
+%sexpected:
+%s`, got, exp)
+ }
+}
+
+const (
+ minLevel = 1
+ maxLevel = 9
+ enrollment = 400
+)
+
+func BenchmarkAddStudents(b *testing.B) {
+ const pool = 1e6 // pool of students
+ names := make([]string, pool)
+ levels := make([]int, pool)
+ for i := range names {
+ names[i] = strconv.Itoa(rand.Intn(1e5))
+ levels[i] = minLevel + rand.Intn(maxLevel-minLevel+1)
+ }
+ p := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ // bench combined time to create a school and add
+ // a number of students, drawn from a pool of students
+ s := New()
+ for t := 0; t < enrollment; t++ {
+ s.Add(names[p], levels[p])
+ p = (p + 1) % pool
+ }
+ }
+}
+
+func BenchmarkEnrollment(b *testing.B) {
+ const pool = 1000 // pool of schools
+ ss := make([]*School, pool)
+ for i := range ss {
+ s := New()
+ for t := 0; t < enrollment; t++ {
+ s.Add(
+ strconv.Itoa(rand.Intn(1e5)),
+ minLevel+rand.Intn(maxLevel-minLevel+1))
+ }
+ ss[i] = s
+ }
+ p := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ // bench time to get enrollment of a full school,
+ // averaged over a pool of schools.
+ ss[p].Enrollment()
+ p = (p + 1) % pool
+ }
+}