diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/cmd/gotest/gotest | 5 | ||||
-rw-r--r-- | src/lib/bufio_test.go | 342 | ||||
-rw-r--r-- | src/lib/sort_test.go | 238 | ||||
-rw-r--r-- | src/lib/strings_test.go | 99 | ||||
-rw-r--r-- | src/lib/time/time_test.go | 79 |
5 files changed, 762 insertions, 1 deletions
diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest index 988e6f4ee..55d22e729 100755 --- a/src/cmd/gotest/gotest +++ b/src/cmd/gotest/gotest @@ -55,7 +55,10 @@ trap "rm -f _testmain.go _testmain.6" 0 1 2 3 14 15 # test array echo echo 'var tests = &[]testing.Test {' - for i in $(6nm -s $ofiles | grep ' T .*·Test' | sed 's/.* //; s/·/./') + # test functions are named TestFoo + # the grep -v eliminates methods and other special names + # that have multiple dots. + for i in $(6nm -s $ofiles | grep ' T .*·Test[A-Z]' | grep -v '·.*[.·]' | sed 's/.* //; s/·/./') do echo ' testing.Test{ "'$i'", &'$i' },' done diff --git a/src/lib/bufio_test.go b/src/lib/bufio_test.go new file mode 100644 index 000000000..8265c0a55 --- /dev/null +++ b/src/lib/bufio_test.go @@ -0,0 +1,342 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bufio + +import ( + "bufio"; + "fmt"; + "io"; + "os"; + "syscall"; + "testing"; +) + +func StringToBytes(s string) *[]byte { + b := new([]byte, len(s)); + for i := 0; i < len(s); i++ { + b[i] = s[i] + } + return b +} + +// Should be in language! +func Copy(p *[]byte, q *[]byte) { + for i := 0; i < len(p); i++ { + p[i] = q[i] + } +} + +// Reads from p. +type ByteReader struct { + p *[]byte +} + +func NewByteReader(p *[]byte) io.Read { + b := new(ByteReader); + b.p = p; + return b +} + +func (b *ByteReader) Read(p *[]byte) (int, *os.Error) { + n := len(p); + if n > len(b.p) { + n = len(b.p) + } + Copy(p[0:n], b.p[0:n]); + b.p = b.p[n:len(b.p)]; + return n, nil +} + + +// Reads from p but only returns half of what you asked for. +type HalfByteReader struct { + p *[]byte +} + +func NewHalfByteReader(p *[]byte) io.Read { + b := new(HalfByteReader); + b.p = p; + return b +} + +func (b *HalfByteReader) Read(p *[]byte) (int, *os.Error) { + n := len(p)/2; + if n == 0 && len(p) > 0 { + n = 1 + } + if n > len(b.p) { + n = len(b.p) + } + Copy(p[0:n], b.p[0:n]); + b.p = b.p[n:len(b.p)]; + return n, nil +} + +// Reads from a reader and rot13s the result. +type Rot13Reader struct { + r io.Read +} + +func NewRot13Reader(r io.Read) *Rot13Reader { + r13 := new(Rot13Reader); + r13.r = r; + return r13 +} + +func (r13 *Rot13Reader) Read(p *[]byte) (int, *os.Error) { + n, e := r13.r.Read(p); + if e != nil { + return n, e + } + for i := 0; i < n; i++ { + if 'a' <= p[i] && p[i] <= 'z' || 'A' <= p[i] && p[i] <= 'Z' { + if 'a' <= p[i] && p[i] <= 'm' || 'A' <= p[i] && p[i] <= 'M' { + p[i] += 13; + } else { + p[i] -= 13; + } + } + } + return n, nil +} + +type Readmaker struct { + name string; + fn *(*[]byte) io.Read; +} +var readmakers = []Readmaker { + Readmaker{ "full", func(p *[]byte) io.Read { return NewByteReader(p) } }, + Readmaker{ "half", func(p *[]byte) io.Read { return NewHalfByteReader(p) } }, +} + +// Call ReadLineString (which ends up calling everything else) +// to accumulate the text of a file. +func ReadLines(b *BufRead) string { + s := ""; + for { + s1, e := b.ReadLineString('\n', true); + if e == EndOfFile { + break + } + if e != nil { + panic("GetLines: "+e.String()) + } + s += s1 + } + return s +} + +// Call ReadByte to accumulate the text of a file +func ReadBytes(buf *BufRead) string { + var b [1000]byte; + nb := 0; + for { + c, e := buf.ReadByte(); + if e == EndOfFile { + break + } + if e != nil { + panic("GetBytes: "+e.String()) + } + b[nb] = c; + nb++; + } + // BUG return string(b[0:nb]) ? + return string(b)[0:nb] +} + +// Call Read to accumulate the text of a file +func Reads(buf *BufRead, m int) string { + var b [1000]byte; + nb := 0; + for { + // BUG parens around (&b) should not be needed + n, e := buf.Read((&b)[nb:nb+m]); + nb += n; + if e == EndOfFile { + break + } + } + return string((&b)[0:nb]) +} + +type Bufreader struct { + name string; + fn *(*BufRead) string; +} +var bufreaders = []Bufreader { + Bufreader{ "1", func(b *BufRead) string { return Reads(b, 1) } }, + Bufreader{ "2", func(b *BufRead) string { return Reads(b, 2) } }, + Bufreader{ "3", func(b *BufRead) string { return Reads(b, 3) } }, + Bufreader{ "4", func(b *BufRead) string { return Reads(b, 4) } }, + Bufreader{ "5", func(b *BufRead) string { return Reads(b, 5) } }, + Bufreader{ "7", func(b *BufRead) string { return Reads(b, 7) } }, + Bufreader{ "bytes", &ReadBytes }, + Bufreader{ "lines", &ReadLines }, +} + +var bufsizes = []int { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 23, 32, 46, 64, 93, 128, 1024, 4096 +} + +export func TestBufReadSimple(t *testing.T) { + b, e := NewBufRead(NewByteReader(StringToBytes("hello world"))); + if s := ReadBytes(b); s != "hello world" { + t.Errorf("simple hello world test failed: got %q", s); + } + + b, e = NewBufRead(NewRot13Reader(NewByteReader(StringToBytes("hello world")))); + if s := ReadBytes(b); s != "uryyb jbeyq" { + t.Error("rot13 hello world test failed: got %q", s); + } +} + +export func TestBufRead(t *testing.T) { + var texts [31]string; + str := ""; + all := ""; + for i := 0; i < len(texts)-1; i++ { + texts[i] = str + "\n"; + all += texts[i]; + str += string(i%26+'a') + } + texts[len(texts)-1] = all; + + for h := 0; h < len(texts); h++ { + text := texts[h]; + textbytes := StringToBytes(text); + for i := 0; i < len(readmakers); i++ { + for j := 0; j < len(bufreaders); j++ { + for k := 0; k < len(bufsizes); k++ { + readmaker := readmakers[i]; + bufreader := bufreaders[j]; + bufsize := bufsizes[k]; + read := readmaker.fn(textbytes); + buf, e := NewBufReadSize(read, bufsize); + s := bufreader.fn(buf); + if s != text { + t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q", + readmaker.name, bufreader.name, bufsize, text, s); + } + } + } + } + } +} + +type WriteBuffer interface { + Write(p *[]byte) (int, *os.Error); + GetBytes() *[]byte +} + +// Accumulates bytes into a byte array. +type ByteWriter struct { + p *[]byte; + n int +} + +func NewByteWriter() WriteBuffer { + return new(ByteWriter) +} + +func (w *ByteWriter) Write(p *[]byte) (int, *os.Error) { + if w.p == nil { + w.p = new([]byte, len(p)+100) + } else if w.n + len(p) >= len(w.p) { + newp := new([]byte, len(w.p)*2 + len(p)); + Copy(newp[0:w.n], w.p[0:w.n]); + w.p = newp + } + Copy(w.p[w.n:w.n+len(p)], p); + w.n += len(p); + return len(p), nil +} + +func (w *ByteWriter) GetBytes() *[]byte { + return w.p[0:w.n] +} + +// Accumulates bytes written into a byte array +// but Write only takes half of what you give it. +// TODO: Could toss this -- Write() is not supposed to do that. +type HalfByteWriter struct { + bw WriteBuffer +} + +func NewHalfByteWriter() WriteBuffer { + w := new(HalfByteWriter); + w.bw = NewByteWriter(); + return w +} + +func (w *HalfByteWriter) Write(p *[]byte) (int, *os.Error) { + n := (len(p)+1) / 2; + // BUG return w.bw.Write(p[0:n]) + r, e := w.bw.Write(p[0:n]); + return r, e +} + +func (w *HalfByteWriter) GetBytes() *[]byte { + return w.bw.GetBytes() +} + +type Writemaker struct { + name string; + fn *()WriteBuffer; +} +export func TestBufWrite(t *testing.T) { + var data [8192]byte; + + var writers = []Writemaker { + Writemaker{ "full", &NewByteWriter }, + Writemaker{ "half", &NewHalfByteWriter }, + }; + + for i := 0; i < len(data); i++ { + data[i] = byte(' '+ i%('~'-' ')); + } + for i := 0; i < len(bufsizes); i++ { + for j := 0; j < len(bufsizes); j++ { + for k := 0; k < len(writers); k++ { + nwrite := bufsizes[i]; + bs := bufsizes[j]; + + // Write nwrite bytes using buffer size bs. + // Check that the right amount makes it out + // and that the data is correct. + + write := writers[k].fn(); + buf, e := NewBufWriteSize(write, bs); + context := fmt.sprintf("write=%s nwrite=%d bufsize=%d", writers[k].name, nwrite, bs); + if e != nil { + t.Errorf("%s: NewBufWriteSize %d: %v", context, bs, e); + continue; + } + n, e1 := buf.Write((&data)[0:nwrite]); + if e1 != nil || n != nwrite { + t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1); + continue; + } + if e = buf.Flush(); e != nil { + t.Errorf("%s: buf.Flush = %v", context, e); + } + + written := write.GetBytes(); + if len(written) != nwrite { + t.Errorf("%s: %d bytes written", context, len(written)); + } + for l := 0; l < len(written); l++ { + if written[i] != data[i] { + t.Errorf("%s: wrong bytes written"); + t.Errorf("want=%s", (&data)[0:len(written)]); + t.Errorf("have=%s", written); + } + } + } + } + } +} + diff --git a/src/lib/sort_test.go b/src/lib/sort_test.go new file mode 100644 index 000000000..5afced699 --- /dev/null +++ b/src/lib/sort_test.go @@ -0,0 +1,238 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sort + +import ( + "fmt"; + "rand"; + "sort"; + "testing"; +) + +func BentleyMcIlroyTests(); + + +var ints = []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} +var floats = []float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} +var strings = []string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} + +export func TestSortIntArray(t *testing.T) { + data := ints; + a := sort.IntArray{&data}; + sort.Sort(&a); + if !sort.IsSorted(&a) { + t.Errorf("sorted %v", ints); + t.Errorf(" got %v", data); + } +} + +export func TestSortFloatArray(t *testing.T) { + data := floats; + a := sort.FloatArray{&data}; + sort.Sort(&a); + if !sort.IsSorted(&a) { + t.Errorf("sorted %v", floats); + t.Errorf(" got %v", data); + } +} + +export func TestSortStringArray(t *testing.T) { + data := strings; + a := sort.StringArray{&data}; + sort.Sort(&a); + if !sort.IsSorted(&a) { + t.Errorf("sorted %v", strings); + t.Errorf(" got %v", data); + } +} + +export func TestSortInts(t *testing.T) { + data := ints; + sort.SortInts(&data); + if !sort.IntsAreSorted(&data) { + t.Errorf("sorted %v", ints); + t.Errorf(" got %v", data); + } +} + +export func TestSortFloats(t *testing.T) { + data := floats; + sort.SortFloats(&data); + if !sort.FloatsAreSorted(&data) { + t.Errorf("sorted %v", floats); + t.Errorf(" got %v", data); + } +} + +export func TestSortStrings(t *testing.T) { + data := strings; + sort.SortStrings(&data); + if !sort.StringsAreSorted(&data) { + t.Errorf("sorted %v", strings); + t.Errorf(" got %v", data); + } +} + +export func TestSortLargeRandom(t *testing.T) { + data := new([]int, 1000000); + for i := 0; i < len(data); i++ { + data[i] = rand.rand() % 100; + } + if sort.IntsAreSorted(data) { + t.Fatalf("terrible rand.rand"); + } + sort.SortInts(data); + if !sort.IntsAreSorted(data) { + t.Errorf("sort didn't sort - 1M ints"); + } +} + +const ( + Sawtooth = iota; + Rand; + Stagger; + Plateau; + Shuffle; + NDist; +) + +const ( + Copy = iota; + Reverse; + ReverseFirstHalf; + ReverseSecondHalf; + Sorted; + Dither; + NMode; +); + +type TestingData struct { + desc string; + t *testing.T; + data *[]int; + maxswap int; // number of swaps allowed + nswap int; +} + +func (d *TestingData) Len() int { return len(d.data); } +func (d *TestingData) Less(i, j int) bool { return d.data[i] < d.data[j]; } +func (d *TestingData) Swap(i, j int) { + if d.nswap >= d.maxswap { + d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data)); + d.t.FailNow(); + } + d.nswap++; + d.data[i], d.data[j] = d.data[j], d.data[i]; +} + +func Lg(n int) int { + i := 0; + for 1<<uint(i) < n { + i++; + } + return i; +} + +func Min(a, b int) int { + if a < b { + return a; + } + return b; +} + +export func TestBentleyMcIlroy(t *testing.T) { + sizes := []int{100, 1023, 1024, 1025}; + dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}; + modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}; + var tmp1, tmp2 [1025]int; + for ni := 0; ni < len(sizes); ni++ { + n := sizes[ni]; + for m := 1; m < 2*n; m *= 2 { + for dist := 0; dist < NDist; dist++ { + j := 0; + k := 1; + data := (&tmp1)[0:n]; + for i := 0; i < n; i++ { + switch dist { + case Sawtooth: + data[i] = i % m; + case Rand: + data[i] = rand.rand() % m; + case Stagger: + data[i] = (i*m + i) % n; + case Plateau: + data[i] = Min(i, m); + case Shuffle: + if rand.rand() % m != 0 { + j += 2; + data[i] = j; + } else { + k += 2; + data[i] = k; + } + } + } + + mdata := (&tmp2)[0:n]; + for mode := 0; mode < NMode; mode++ { + switch mode { + case Copy: + for i := 0; i < n; i++ { + mdata[i] = data[i]; + } + case Reverse: + for i := 0; i < n; i++ { + mdata[i] = data[n-i-1]; + } + case ReverseFirstHalf: + for i := 0; i < n/2; i++ { + mdata[i] = data[n/2-i-1]; + } + for i := n/2; i < n; i++ { + mdata[i] = data[i]; + } + case ReverseSecondHalf: + for i := 0; i < n/2; i++ { + mdata[i] = data[i]; + } + for i := n/2; i < n; i++ { + mdata[i] = data[n-(i-n/2)-1]; + } + case Sorted: + for i := 0; i < n; i++ { + mdata[i] = data[i]; + } + // sort.SortInts is known to be correct + // because mode Sort runs after mode Copy. + sort.SortInts(mdata); + case Dither: + for i := 0; i < n; i++ { + mdata[i] = data[i] + i%5; + } + } + + desc := fmt.sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode]); + d := &TestingData{desc, t, mdata[0:n], n*Lg(n)*12/10, 0}; + sort.Sort(d); + + // If we were testing C qsort, we'd have to make a copy + // of the array and sort it ourselves and then compare + // x against it, to ensure that qsort was only permuting + // the data, not (for example) overwriting it with zeros. + // + // In go, we don't have to be so paranoid: since the only + // mutating method sort.Sort can call is TestingData.swap, + // it suffices here just to check that the final array is sorted. + if !sort.IntsAreSorted(mdata) { + t.Errorf("%s: ints not sorted", desc); + t.Errorf("\t%v", mdata); + t.FailNow(); + } + } + } + } + } +} + diff --git a/src/lib/strings_test.go b/src/lib/strings_test.go new file mode 100644 index 000000000..a7b63738b --- /dev/null +++ b/src/lib/strings_test.go @@ -0,0 +1,99 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import ( + "strings"; + "testing"; +) + +func eq(a, b *[]string) bool { + if len(a) != len(b) { + return false; + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false; + } + } + return true; +} + +var abcd = "abcd"; +var faces = "☺☻☹"; +var commas = "1,2,3,4"; +var dots = "1....2....3....4"; + +type ExplodeTest struct { + s string; + a *[]string; +} +var explodetests = []ExplodeTest { + ExplodeTest{ abcd, &[]string{"a", "b", "c", "d"} }, + ExplodeTest{ faces, &[]string{"☺", "☻", "☹" } }, +} +export func TestExplode(t *testing.T) { + for i := 0; i < len(explodetests); i++ { + tt := explodetests[i]; + a := explode(tt.s); + if !eq(a, tt.a) { + t.Errorf("Explode(%q) = %v; want %v", tt.s, a, tt.a); + continue; + } + s := join(a, ""); + if s != tt.s { + t.Errorf(`Join(Explode(%q), "") = %q`, tt.s, s); + } + } +} + +type SplitTest struct { + s string; + sep string; + a *[]string; +} +var splittests = []SplitTest { + SplitTest{ abcd, "a", &[]string{"", "bcd"} }, + SplitTest{ abcd, "z", &[]string{"abcd"} }, + SplitTest{ abcd, "", &[]string{"a", "b", "c", "d"} }, + SplitTest{ commas, ",", &[]string{"1", "2", "3", "4"} }, + SplitTest{ dots, "...", &[]string{"1", ".2", ".3", ".4"} }, + SplitTest{ faces, "☹", &[]string{"☺☻", ""} }, + SplitTest{ faces, "~", &[]string{faces} }, + SplitTest{ faces, "", &[]string{"☺", "☻", "☹"} }, +} +export func TestSplit(t *testing.T) { + for i := 0; i < len(splittests); i++ { + tt := splittests[i]; + a := split(tt.s, tt.sep); + if !eq(a, tt.a) { + t.Errorf("Split(%q, %q) = %v; want %v", tt.s, tt.sep, a, tt.a); + continue; + } + s := join(a, tt.sep); + if s != tt.s { + t.Errorf("Join(Split(%q, %q), %q) = %q", tt.s, tt.sep, tt.sep, s); + } + } +} + +// TODO: utflen shouldn't even be in strings. +type UtflenTest struct { + in string; + out int; +} +var utflentests = []UtflenTest { + UtflenTest{ abcd, 4 }, + UtflenTest{ faces, 3 }, + UtflenTest{ commas, 7 }, +} +export func TestUtflen(t *testing.T) { + for i := 0; i < len(utflentests); i++ { + tt := utflentests[i]; + if out := strings.utflen(tt.in); out != tt.out { + t.Errorf("utflen(%q) = %d, want %d", tt.in, out, tt.out); + } + } +} diff --git a/src/lib/time/time_test.go b/src/lib/time/time_test.go new file mode 100644 index 000000000..f771ec03c --- /dev/null +++ b/src/lib/time/time_test.go @@ -0,0 +1,79 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// $G $F.go && $L $F.$A && ./$A.out + +package time + +import ( + "testing"; + "time"; +) + +type TimeTest struct { + seconds int64; + golden Time; +} + +var utctests = []TimeTest { + TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "GMT"}}, + TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "GMT"}}, + TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "GMT"}}, + TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "GMT"}}, + TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "GMT"}}, + TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "GMT"}}, + TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "GMT"}} +} + +var localtests = []TimeTest { + TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST"}}, + TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"}} +} + +func Same(t, u *Time) bool { + return t.year == u.year + && t.month == u.month + && t.day == u.day + && t.hour == u.hour + && t.minute == u.minute + && t.second == u.second + && t.weekday == u.weekday + && t.zoneoffset == u.zoneoffset + && t.zone == u.zone +} + +export func TestSecondsToUTC(t *testing.T) { + for i := 0; i < len(utctests); i++ { + sec := utctests[i].seconds; + golden := &utctests[i].golden; + tm := SecondsToUTC(sec); + newsec := tm.Seconds(); + if newsec != sec { + t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec); + } + if !Same(tm, golden) { + t.Errorf("SecondsToUTC(%d):", sec); + t.Errorf(" want=%v", *golden); + t.Errorf(" have=%v", *tm); + } + } +} + +export func TestSecondsToLocalTime(t *testing.T) { + for i := 0; i < len(localtests); i++ { + sec := localtests[i].seconds; + golden := &localtests[i].golden; + tm := SecondsToLocalTime(sec); + newsec := tm.Seconds(); + if newsec != sec { + t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec); + } + if !Same(tm, golden) { + t.Errorf("SecondsToLocalTime(%d):", sec); + t.Errorf(" want=%v", *golden); + t.Errorf(" have=%v", *tm); + } + } +} + |