mirror of https://go.googlesource.com/go
130 lines
3.1 KiB
Go
130 lines
3.1 KiB
Go
// Copyright 2019 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 runtime_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"internal/testenv"
|
|
"os/exec"
|
|
"reflect"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFakeTime(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("faketime not supported on windows")
|
|
}
|
|
|
|
// Faketime is advanced in checkdead. External linking brings in cgo,
|
|
// causing checkdead not working.
|
|
testenv.MustInternalLink(t, false)
|
|
|
|
t.Parallel()
|
|
|
|
exe, err := buildTestProg(t, "testfaketime", "-tags=faketime")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
cmd := exec.Command(exe)
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
|
|
err = testenv.CleanCmdEnv(cmd).Run()
|
|
if err != nil {
|
|
t.Fatalf("exit status: %v\n%s", err, stderr.String())
|
|
}
|
|
|
|
t.Logf("raw stdout: %q", stdout.String())
|
|
t.Logf("raw stderr: %q", stderr.String())
|
|
|
|
f1, err1 := parseFakeTime(stdout.Bytes())
|
|
if err1 != nil {
|
|
t.Fatal(err1)
|
|
}
|
|
f2, err2 := parseFakeTime(stderr.Bytes())
|
|
if err2 != nil {
|
|
t.Fatal(err2)
|
|
}
|
|
|
|
const time0 = 1257894000000000000
|
|
got := [][]fakeTimeFrame{f1, f2}
|
|
var want = [][]fakeTimeFrame{{
|
|
{time0 + 1, "line 2\n"},
|
|
{time0 + 1, "line 3\n"},
|
|
{time0 + 1e9, "line 5\n"},
|
|
{time0 + 1e9, "2009-11-10T23:00:01Z"},
|
|
}, {
|
|
{time0, "line 1\n"},
|
|
{time0 + 2, "line 4\n"},
|
|
}}
|
|
if !reflect.DeepEqual(want, got) {
|
|
t.Fatalf("want %v, got %v", want, got)
|
|
}
|
|
}
|
|
|
|
type fakeTimeFrame struct {
|
|
time uint64
|
|
data string
|
|
}
|
|
|
|
func parseFakeTime(x []byte) ([]fakeTimeFrame, error) {
|
|
var frames []fakeTimeFrame
|
|
for len(x) != 0 {
|
|
if len(x) < 4+8+4 {
|
|
return nil, errors.New("truncated header")
|
|
}
|
|
const magic = "\x00\x00PB"
|
|
if string(x[:len(magic)]) != magic {
|
|
return nil, errors.New("bad magic")
|
|
}
|
|
x = x[len(magic):]
|
|
time := binary.BigEndian.Uint64(x)
|
|
x = x[8:]
|
|
dlen := binary.BigEndian.Uint32(x)
|
|
x = x[4:]
|
|
data := string(x[:dlen])
|
|
x = x[dlen:]
|
|
frames = append(frames, fakeTimeFrame{time, data})
|
|
}
|
|
return frames, nil
|
|
}
|
|
|
|
func TestTimeTimerType(t *testing.T) {
|
|
// runtime.timeTimer (exported for testing as TimeTimer)
|
|
// must have time.Timer and time.Ticker as a prefix
|
|
// (meaning those two must have the same layout).
|
|
runtimeTimeTimer := reflect.TypeOf(runtime.TimeTimer{})
|
|
|
|
check := func(name string, typ reflect.Type) {
|
|
n1 := runtimeTimeTimer.NumField()
|
|
n2 := typ.NumField()
|
|
if n1 != n2+1 {
|
|
t.Errorf("runtime.TimeTimer has %d fields, want %d (%s has %d fields)", n1, n2+1, name, n2)
|
|
return
|
|
}
|
|
for i := 0; i < n2; i++ {
|
|
f1 := runtimeTimeTimer.Field(i)
|
|
f2 := typ.Field(i)
|
|
t1 := f1.Type
|
|
t2 := f2.Type
|
|
if t1 != t2 && !(t1.Kind() == reflect.UnsafePointer && t2.Kind() == reflect.Chan) {
|
|
t.Errorf("runtime.Timer field %s %v incompatible with %s field %s %v", f1.Name, t1, name, f2.Name, t2)
|
|
}
|
|
if f1.Offset != f2.Offset {
|
|
t.Errorf("runtime.Timer field %s offset %d incompatible with %s field %s offset %d", f1.Name, f1.Offset, name, f2.Name, f2.Offset)
|
|
}
|
|
}
|
|
}
|
|
|
|
check("time.Timer", reflect.TypeOf(time.Timer{}))
|
|
check("time.Ticker", reflect.TypeOf(time.Ticker{}))
|
|
}
|