Home | History | Annotate | Download | only in log
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package log
      6 
      7 // These tests are too simple.
      8 
      9 import (
     10 	"bytes"
     11 	"fmt"
     12 	"os"
     13 	"regexp"
     14 	"strings"
     15 	"testing"
     16 	"time"
     17 )
     18 
     19 const (
     20 	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
     21 	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
     22 	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
     23 	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
     24 	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
     25 	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
     26 )
     27 
     28 type tester struct {
     29 	flag    int
     30 	prefix  string
     31 	pattern string // regexp that log output must match; we add ^ and expected_text$ always
     32 }
     33 
     34 var tests = []tester{
     35 	// individual pieces:
     36 	{0, "", ""},
     37 	{0, "XXX", "XXX"},
     38 	{Ldate, "", Rdate + " "},
     39 	{Ltime, "", Rtime + " "},
     40 	{Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
     41 	{Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
     42 	{Llongfile, "", Rlongfile + " "},
     43 	{Lshortfile, "", Rshortfile + " "},
     44 	{Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
     45 	// everything at once:
     46 	{Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
     47 	{Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
     48 }
     49 
     50 // Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
     51 func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
     52 	buf := new(bytes.Buffer)
     53 	SetOutput(buf)
     54 	SetFlags(flag)
     55 	SetPrefix(prefix)
     56 	if useFormat {
     57 		Printf("hello %d world", 23)
     58 	} else {
     59 		Println("hello", 23, "world")
     60 	}
     61 	line := buf.String()
     62 	line = line[0 : len(line)-1]
     63 	pattern = "^" + pattern + "hello 23 world$"
     64 	matched, err4 := regexp.MatchString(pattern, line)
     65 	if err4 != nil {
     66 		t.Fatal("pattern did not compile:", err4)
     67 	}
     68 	if !matched {
     69 		t.Errorf("log output should match %q is %q", pattern, line)
     70 	}
     71 	SetOutput(os.Stderr)
     72 }
     73 
     74 func TestAll(t *testing.T) {
     75 	for _, testcase := range tests {
     76 		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
     77 		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
     78 	}
     79 }
     80 
     81 func TestOutput(t *testing.T) {
     82 	const testString = "test"
     83 	var b bytes.Buffer
     84 	l := New(&b, "", 0)
     85 	l.Println(testString)
     86 	if expect := testString + "\n"; b.String() != expect {
     87 		t.Errorf("log output should match %q is %q", expect, b.String())
     88 	}
     89 }
     90 
     91 func TestFlagAndPrefixSetting(t *testing.T) {
     92 	var b bytes.Buffer
     93 	l := New(&b, "Test:", LstdFlags)
     94 	f := l.Flags()
     95 	if f != LstdFlags {
     96 		t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
     97 	}
     98 	l.SetFlags(f | Lmicroseconds)
     99 	f = l.Flags()
    100 	if f != LstdFlags|Lmicroseconds {
    101 		t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
    102 	}
    103 	p := l.Prefix()
    104 	if p != "Test:" {
    105 		t.Errorf(`Prefix: expected "Test:" got %q`, p)
    106 	}
    107 	l.SetPrefix("Reality:")
    108 	p = l.Prefix()
    109 	if p != "Reality:" {
    110 		t.Errorf(`Prefix: expected "Reality:" got %q`, p)
    111 	}
    112 	// Verify a log message looks right, with our prefix and microseconds present.
    113 	l.Print("hello")
    114 	pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
    115 	matched, err := regexp.Match(pattern, b.Bytes())
    116 	if err != nil {
    117 		t.Fatalf("pattern %q did not compile: %s", pattern, err)
    118 	}
    119 	if !matched {
    120 		t.Error("message did not match pattern")
    121 	}
    122 }
    123 
    124 func TestUTCFlag(t *testing.T) {
    125 	var b bytes.Buffer
    126 	l := New(&b, "Test:", LstdFlags)
    127 	l.SetFlags(Ldate | Ltime | LUTC)
    128 	// Verify a log message looks right in the right time zone. Quantize to the second only.
    129 	now := time.Now().UTC()
    130 	l.Print("hello")
    131 	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
    132 		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
    133 	got := b.String()
    134 	if got == want {
    135 		return
    136 	}
    137 	// It's possible we crossed a second boundary between getting now and logging,
    138 	// so add a second and try again. This should very nearly always work.
    139 	now = now.Add(time.Second)
    140 	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
    141 		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
    142 	if got == want {
    143 		return
    144 	}
    145 	t.Errorf("got %q; want %q", got, want)
    146 }
    147 
    148 func TestEmptyPrintCreatesLine(t *testing.T) {
    149 	var b bytes.Buffer
    150 	l := New(&b, "Header:", LstdFlags)
    151 	l.Print()
    152 	l.Println("non-empty")
    153 	output := b.String()
    154 	if n := strings.Count(output, "Header"); n != 2 {
    155 		t.Errorf("expected 2 headers, got %d", n)
    156 	}
    157 	if n := strings.Count(output, "\n"); n != 2 {
    158 		t.Errorf("expected 2 lines, got %d", n)
    159 	}
    160 }
    161 
    162 func BenchmarkItoa(b *testing.B) {
    163 	dst := make([]byte, 0, 64)
    164 	for i := 0; i < b.N; i++ {
    165 		dst = dst[0:0]
    166 		itoa(&dst, 2015, 4)   // year
    167 		itoa(&dst, 1, 2)      // month
    168 		itoa(&dst, 30, 2)     // day
    169 		itoa(&dst, 12, 2)     // hour
    170 		itoa(&dst, 56, 2)     // minute
    171 		itoa(&dst, 0, 2)      // second
    172 		itoa(&dst, 987654, 6) // microsecond
    173 	}
    174 }
    175 
    176 func BenchmarkPrintln(b *testing.B) {
    177 	const testString = "test"
    178 	var buf bytes.Buffer
    179 	l := New(&buf, "", LstdFlags)
    180 	for i := 0; i < b.N; i++ {
    181 		buf.Reset()
    182 		l.Println(testString)
    183 	}
    184 }
    185