<commit_before>package logger

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"net/http/httptest"
	"sort"
	"strings"
	"testing"
	"time"
)

var strMarshalError = "Static Marshaling Test Error"

func withTime(t time.Time) OptFunc {
	return func(l *logger) {
		l.ts = &t
	}
}

func withStdErr(b *bytes.Buffer) OptFunc {
	return func(l *logger) {
		l.stderr = b
	}
}

func withStdOut(b *bytes.Buffer) OptFunc {
	return func(l *logger) {
		l.stdout = b
	}
}

func withFatal(l *logger) {
	l.fatal = func(i int) {}
}

func errorMarshal(i interface{}) ([]byte, error) {
	return nil, errors.New(strMarshalError)
}

func TestMultipleOutput(t *testing.T) {

	want := []string{
		"TEST \x1b[32m Info: This is a test \x1b[0m\n",
		"TEST \x1b[33m Warn: This is a test \x1b[0m\n",
		"TEST \x1b[31m Error: This is a test \x1b[0m\n",
		"TEST \x1b[36m Debug: This is a test \x1b[0m\n",
		"TEST \x1b[34m Trace: This is a test \x1b[0m\n",
		"TEST \x1b[31m Fatal: This is a test \x1b[0m\n",
		"TEST \x1b[35m Info: This is a test \x1b[0m\n",
	}

	have := new(bytes.Buffer)

	type tt func(...interface{})
	l := New(WithOutput(have), WithTimeFormat("TEST"), withFatal)
	for i, lg := range []tt{l.Info, l.Warn, l.Error, l.Debug, l.Trace, l.Fatal} {
		have.Reset()
		lg("This is", "a test")
		if want[i] != have.String() {
			t.Logf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	// check if can use color (but don't evaluate before other tests)
	have.Reset()
	l.Color(Magenta).Info("This is", "a test")

	x := len(want) - 1
	if want[x] != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want[x], have.String())
	}
}

func TestMultipleShortOutput(t *testing.T) {

	want := []string{
		"TEST \x1b[32m [INF] This is a test \x1b[0m\n",
		"TEST \x1b[33m [WRN] This is a test \x1b[0m\n",
		"TEST \x1b[31m [ERR] This is a test \x1b[0m\n",
		"TEST \x1b[36m [DBG] This is a test \x1b[0m\n",
		"TEST \x1b[34m [TRC] This is a test \x1b[0m\n",
		"TEST \x1b[31m [FAT] This is a test \x1b[0m\n",
		"TEST \x1b[35m [INF] This is a test \x1b[0m\n",
	}

	have := new(bytes.Buffer)

	type tt func(...interface{})
	l := New(WithOutput(have), WithShortPrefix, WithTimeFormat("TEST"), withFatal)
	for i, lg := range []tt{l.Info, l.Warn, l.Error, l.Debug, l.Trace, l.Fatal} {
		have.Reset()
		lg("This is", "a test")
		if want[i] != have.String() {
			t.Logf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	// check if can use color (but don't evaluate before other tests)
	have.Reset()
	l.Color(Magenta).Info("This is", "a test")

	x := len(want) - 1
	if want[x] != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want[x], have.String())
	}
}

func TestFilteredOutput(t *testing.T) {
	want := "TEST \x1b[32m Info: This is a simple test [1] \x1b[0m\nTEST \x1b[32m Info: This is a simple test [2] \x1b[0m\n"
	have := new(bytes.Buffer)

	fn := func(s string) bool {
		return !strings.Contains(s, "skip")
	}

	l := New(WithFilteredOutput(fn, have), WithTimeFormat("TEST"))

	l.Info("This is a simple test [1]")
	l.Info("This is a simple test that I skip")
	l.Info("This is a simple test [2]")

	if want != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want, have.String())
	}
}

func TestKVFieldsOutput(t *testing.T) {
	want := []string{
		"TEST \x1b[32m Info: Yes we KV log \x1b[0m basic=3 happy=people quarter=[pound flip]\n",
		"TEST \x1b[32m Info: Yes we KV log \x1b[0m {\"basic\":3,\"happy\":\"people\",\"quarter\":[\"pound\",\"flip\"]}\n",
	}
	have := new(bytes.Buffer)

	l := []Logger{
		New(WithOutput(have), WithTimeFormat("TEST")),
		New(WithOutput(have), WithTimeFormat("TEST"), WithKVMarshaler(json.Marshal)),
	}

	for i := range want {
		have.Reset()
		l[i].Field("happy", "people").Field("basic", 3).Field("quarter", []string{"pound", "flip"}).Info("Yes we KV log")
		if want[i] != have.String() {
			t.Errorf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	for i := range want {
		have.Reset()
		l[i].Fields(KV("happy", "people"), KV("basic", 3), KV("quarter", []string{"pound", "flip"})).Info("Yes we KV log")
		if want[i] != have.String() {
			t.Errorf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	for i := range want {
		have.Reset()
		l[i].Fields(KVMap(KeyValues{
			"happy":   "people",
			"basic":   3,
			"quarter": []string{"pound", "flip"},
		})...).Info("Yes we KV log")<commit_msg>Updated the KV Field tests to be more valid.<commit_after>package logger

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"net/http/httptest"
	"sort"
	"strings"
	"testing"
	"time"
)

var strMarshalError = "Static Marshaling Test Error"

func withTime(t time.Time) OptFunc {
	return func(l *logger) {
		l.ts = &t
	}
}

func withStdErr(b *bytes.Buffer) OptFunc {
	return func(l *logger) {
		l.stderr = b
	}
}

func withStdOut(b *bytes.Buffer) OptFunc {
	return func(l *logger) {
		l.stdout = b
	}
}

func withFatal(l *logger) {
	l.fatal = func(i int) {}
}

func errorMarshal(i interface{}) ([]byte, error) {
	return nil, errors.New(strMarshalError)
}

func TestMultipleOutput(t *testing.T) {

	want := []string{
		"TEST \x1b[32m Info: This is a test \x1b[0m\n",
		"TEST \x1b[33m Warn: This is a test \x1b[0m\n",
		"TEST \x1b[31m Error: This is a test \x1b[0m\n",
		"TEST \x1b[36m Debug: This is a test \x1b[0m\n",
		"TEST \x1b[34m Trace: This is a test \x1b[0m\n",
		"TEST \x1b[31m Fatal: This is a test \x1b[0m\n",
		"TEST \x1b[35m Info: This is a test \x1b[0m\n",
	}

	have := new(bytes.Buffer)

	type tt func(...interface{})
	l := New(WithOutput(have), WithTimeFormat("TEST"), withFatal)
	for i, lg := range []tt{l.Info, l.Warn, l.Error, l.Debug, l.Trace, l.Fatal} {
		have.Reset()
		lg("This is", "a test")
		if want[i] != have.String() {
			t.Logf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	// check if can use color (but don't evaluate before other tests)
	have.Reset()
	l.Color(Magenta).Info("This is", "a test")

	x := len(want) - 1
	if want[x] != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want[x], have.String())
	}
}

func TestMultipleShortOutput(t *testing.T) {

	want := []string{
		"TEST \x1b[32m [INF] This is a test \x1b[0m\n",
		"TEST \x1b[33m [WRN] This is a test \x1b[0m\n",
		"TEST \x1b[31m [ERR] This is a test \x1b[0m\n",
		"TEST \x1b[36m [DBG] This is a test \x1b[0m\n",
		"TEST \x1b[34m [TRC] This is a test \x1b[0m\n",
		"TEST \x1b[31m [FAT] This is a test \x1b[0m\n",
		"TEST \x1b[35m [INF] This is a test \x1b[0m\n",
	}

	have := new(bytes.Buffer)

	type tt func(...interface{})
	l := New(WithOutput(have), WithShortPrefix, WithTimeFormat("TEST"), withFatal)
	for i, lg := range []tt{l.Info, l.Warn, l.Error, l.Debug, l.Trace, l.Fatal} {
		have.Reset()
		lg("This is", "a test")
		if want[i] != have.String() {
			t.Logf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	// check if can use color (but don't evaluate before other tests)
	have.Reset()
	l.Color(Magenta).Info("This is", "a test")

	x := len(want) - 1
	if want[x] != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want[x], have.String())
	}
}

func TestFilteredOutput(t *testing.T) {
	want := "TEST \x1b[32m Info: This is a simple test [1] \x1b[0m\nTEST \x1b[32m Info: This is a simple test [2] \x1b[0m\n"
	have := new(bytes.Buffer)

	fn := func(s string) bool {
		return !strings.Contains(s, "skip")
	}

	l := New(WithFilteredOutput(fn, have), WithTimeFormat("TEST"))

	l.Info("This is a simple test [1]")
	l.Info("This is a simple test that I skip")
	l.Info("This is a simple test [2]")

	if want != have.String() {
		t.Logf("\nwant: %q\n\nhave: %q\n", want, have.String())
	}
}

func TestKVFieldsOutput(t *testing.T) {
	want := []string{
		"TEST \x1b[32m Info: Yes we KV log \x1b[0m basic=3 happy=people quarter=[pound flip]\n",
		"TEST \x1b[32m Info: Yes we KV log \x1b[0m {\"basic\":3,\"happy\":\"people\",\"quarter\":[\"pound\",\"flip\"]}\n",
	}
	have := new(bytes.Buffer)

	l := []Logger{
		New(WithOutput(have), WithTimeFormat("TEST")),
		New(WithOutput(have), WithTimeFormat("TEST"), WithKVMarshaler(json.Marshal)),
	}

	for i := range want {
		have.Reset()
		l[i].Field("happy", "people").Field("basic", 3).Field("quarter", []string{"pound", "flip"})
		l[i].Info("Yes we KV log")

		if want[i] != have.String() {
			t.Errorf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	for i := range want {
		have.Reset()
		l[i].Fields(KV("happy", "people"), KV("basic", 3), KV("quarter", []string{"pound", "flip"}))
		l[i].Info("Yes we KV log")

		if want[i] != have.String() {
			t.Errorf("\nwant: %q\n\nhave: %q\n", want[i], have.String())
		}
	}

	for i := range want {
		have.Reset()
		l[i].Fields(KVMap(KeyValues{
			"happy":   "people",
			"basic":   3,
			"quarter": []string{"pound", "flip"},
		})...)
		l[i].Info("Yes we KV log")

{'fraction_non_alphanumeric': 0.21174195016497896, 'fraction_numerical': 0.022983274547730116, 'mean_word_length': 3.5828988529718457, 'pattern_counts': {'":': 12, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2431377', 'n_tokens_mistral': 4048, 'n_tokens_neox': 3796, 'n_words': 935}