Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 1 | package testutil |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 5 | "path/filepath" |
| 6 | "runtime" |
Jiri Simsa | 870ddd6 | 2014-06-27 14:56:58 -0700 | [diff] [blame] | 7 | "sync" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 8 | ) |
| 9 | |
Jiri Simsa | 870ddd6 | 2014-06-27 14:56:58 -0700 | [diff] [blame] | 10 | var ( |
| 11 | random []byte |
| 12 | randomMutex sync.Mutex |
| 13 | ) |
| 14 | |
| 15 | func generateRandomBytes(size int) []byte { |
| 16 | buffer := make([]byte, size) |
| 17 | offset := 0 |
| 18 | for { |
| 19 | bits := int64(Rand.Int63()) |
| 20 | for i := 0; i < 8; i++ { |
| 21 | buffer[offset] = byte(bits & 0xff) |
| 22 | size-- |
| 23 | if size == 0 { |
| 24 | return buffer |
| 25 | } |
| 26 | offset++ |
| 27 | bits >>= 8 |
| 28 | } |
| 29 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 30 | } |
| 31 | |
| 32 | // DepthToExternalCaller determines the number of stack frames to the first |
| 33 | // enclosing caller that is external to the package that this function is |
| 34 | // called from. Drectory name is used as a proxy for package name, |
| 35 | // that is, the directory component of the file return runtime.Caller is |
| 36 | // compared to that of the lowest level caller until a different one is |
| 37 | // encountered as the stack is walked upwards. |
| 38 | func DepthToExternalCaller() int { |
| 39 | _, file, _, _ := runtime.Caller(1) |
| 40 | cwd := filepath.Dir(file) |
| 41 | for d := 2; d < 10; d++ { |
| 42 | _, file, _, _ := runtime.Caller(d) |
| 43 | if cwd != filepath.Dir(file) { |
| 44 | return d |
| 45 | } |
| 46 | } |
| 47 | return 1 |
| 48 | } |
| 49 | |
Jiri Simsa | 870ddd6 | 2014-06-27 14:56:58 -0700 | [diff] [blame] | 50 | // FormatLogLine will prepend the file and line number of the caller |
| 51 | // at the specificied depth (as per runtime.Caller) to the supplied |
| 52 | // format and args and return a formatted string. It is useful when |
| 53 | // implementing functions that factor out error handling and reporting |
| 54 | // in tests. |
| 55 | func FormatLogLine(depth int, format string, args ...interface{}) string { |
| 56 | _, file, line, _ := runtime.Caller(depth) |
| 57 | nargs := []interface{}{filepath.Base(file), line} |
| 58 | nargs = append(nargs, args...) |
| 59 | return fmt.Sprintf("%s:%d: "+format, nargs...) |
Ankur | 53fdf56 | 2014-05-16 10:03:49 -0700 | [diff] [blame] | 60 | } |
| 61 | |
Jiri Simsa | 870ddd6 | 2014-06-27 14:56:58 -0700 | [diff] [blame] | 62 | // RandomBytes generates the given number of random bytes. |
| 63 | func RandomBytes(size int) []byte { |
| 64 | buffer := make([]byte, size) |
| 65 | randomMutex.Lock() |
| 66 | defer randomMutex.Unlock() |
| 67 | // Generate a 10MB of random bytes since that is a value commonly |
| 68 | // used in the tests. |
| 69 | if len(random) == 0 { |
| 70 | random = generateRandomBytes(10 << 20) |
| 71 | } |
| 72 | if size > len(random) { |
| 73 | extra := generateRandomBytes(size - len(random)) |
| 74 | random = append(random, extra...) |
| 75 | } |
| 76 | start := Rand.Intn(len(random) - size + 1) |
| 77 | copy(buffer, random[start:start+size]) |
| 78 | return buffer |
| 79 | } |