// 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.

// TODO(austin): All of these tests are skipped if the debuglog build
// tag isn't provided. That means we basically never test debuglog.
// There are two potential ways around this:
//
// 1. Make these tests re-build the runtime test with the debuglog
// build tag and re-invoke themselves.
//
// 2. Always build the whole debuglog infrastructure and depend on
// linker dead-code elimination to drop it. This is easy for dlog()
// since there won't be any calls to it. For printDebugLog, we can
// make panic call a wrapper that is call printDebugLog if the
// debuglog build tag is set, or otherwise do nothing. Then tests
// could call printDebugLog directly. This is the right answer in
// principle, but currently our linker reads in all symbols
// regardless, so this would slow down and bloat all links. If the
// linker gets more efficient about this, we should revisit this
// approach.

package runtime_test

import (
	"bytes"
	"fmt"
	"regexp"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
)

func skipDebugLog(t *testing.T) {
	if !runtime.DlogEnabled {
		t.Skip("debug log disabled (rebuild with -tags debuglog)")
	}
}

func dlogCanonicalize(x string) string {
	begin := regexp.MustCompile(`(?m)^>> begin log \d+ <<\n`)
	x = begin.ReplaceAllString(x, "")
	prefix := regexp.MustCompile(`(?m)^\[[^]]+\]`)
	x = prefix.ReplaceAllString(x, "[]")
	return x
}

func TestDebugLog(t *testing.T) {
	skipDebugLog(t)
	runtime.ResetDebugLog()
	runtime.Dlog().S("testing").End()
	got := dlogCanonicalize(runtime.DumpDebugLog())
	if want := "[] testing\n"; got != want {
		t.Fatalf("want %q, got %q", want, got)
	}
}

func TestDebugLogTypes(t *testing.T) {
	skipDebugLog(t)
	runtime.ResetDebugLog()
	var varString = strings.Repeat("a", 4)
	runtime.Dlog().B(true).B(false).I(-42).I16(0x7fff).U64(^uint64(0)).Hex(0xfff).P(nil).S(varString).S("const string").End()
	got := dlogCanonicalize(runtime.DumpDebugLog())
	if want := "[] true false -42 32767 18446744073709551615 0xfff 0x0 aaaa const string\n"; got != want {
		t.Fatalf("want %q, got %q", want, got)
	}
}

func TestDebugLogSym(t *testing.T) {
	skipDebugLog(t)
	runtime.ResetDebugLog()
	pc, _, _, _ := runtime.Caller(0)
	runtime.Dlog().PC(pc).End()
	got := dlogCanonicalize(runtime.DumpDebugLog())
	want := regexp.MustCompile(`\[\] 0x[0-9a-f]+ \[runtime_test\.TestDebugLogSym\+0x[0-9a-f]+ .*/debuglog_test\.go:[0-9]+\]\n`)
	if !want.MatchString(got) {
		t.Fatalf("want matching %s, got %q", want, got)
	}
}

func TestDebugLogInterleaving(t *testing.T) {
	skipDebugLog(t)
	runtime.ResetDebugLog()
	var wg sync.WaitGroup
	done := int32(0)
	wg.Add(1)
	go func() {
		// Encourage main goroutine to move around to
		// different Ms and Ps.
		for atomic.LoadInt32(&done) == 0 {
			runtime.Gosched()
		}
		wg.Done()
	}()
	var want bytes.Buffer
	for i := 0; i < 1000; i++ {
		runtime.Dlog().I(i).End()
		fmt.Fprintf(&want, "[] %d\n", i)
		runtime.Gosched()
	}
	atomic.StoreInt32(&done, 1)
	wg.Wait()

	gotFull := runtime.DumpDebugLog()
	got := dlogCanonicalize(gotFull)
	if got != want.String() {
		// Since the timestamps are useful in understand
		// failures of this test, we print the uncanonicalized
		// output.
		t.Fatalf("want %q, got (uncanonicalized) %q", want.String(), gotFull)
	}
}

func TestDebugLogWraparound(t *testing.T) {
	skipDebugLog(t)

	// Make sure we don't switch logs so it's easier to fill one up.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	runtime.ResetDebugLog()
	var longString = strings.Repeat("a", 128)
	var want bytes.Buffer
	for i, j := 0, 0; j < 2*runtime.DebugLogBytes; i, j = i+1, j+len(longString) {
		runtime.Dlog().I(i).S(longString).End()
		fmt.Fprintf(&want, "[] %d %s\n", i, longString)
	}
	log := runtime.DumpDebugLog()

	// Check for "lost" message.
	lost := regexp.MustCompile(`^>> begin log \d+; lost first \d+KB <<\n`)
	if !lost.MatchString(log) {
		t.Fatalf("want matching %s, got %q", lost, log)
	}
	idx := lost.FindStringIndex(log)
	// Strip lost message.
	log = dlogCanonicalize(log[idx[1]:])

	// Check log.
	if !strings.HasSuffix(want.String(), log) {
		t.Fatalf("wrong suffix:\n%s", log)
	}
}

func TestDebugLogLongString(t *testing.T) {
	skipDebugLog(t)

	runtime.ResetDebugLog()
	var longString = strings.Repeat("a", runtime.DebugLogStringLimit+1)
	runtime.Dlog().S(longString).End()
	got := dlogCanonicalize(runtime.DumpDebugLog())
	want := "[] " + strings.Repeat("a", runtime.DebugLogStringLimit) + " ..(1 more bytes)..\n"
	if got != want {
		t.Fatalf("want %q, got %q", want, got)
	}
}
