The log level condition was corrected to ensure proper comparisons. Added a full suite of unit tests to validate logging functionality, error handling, and edge cases, ensuring consistent and reliable behavior of the logging module.
304 lines
7.7 KiB
Go
304 lines
7.7 KiB
Go
package lol
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLogLevels(t *testing.T) {
|
|
// Test that log levels are correctly ordered
|
|
if !(Off < Fatal && Fatal < Error && Error < Warn && Warn < Info && Info < Debug && Debug < Trace) {
|
|
t.Error("Log levels are not correctly ordered")
|
|
}
|
|
|
|
// Test that LevelNames matches the constants
|
|
expectedLevelNames := []string{"off", "fatal", "error", "warn", "info", "debug", "trace"}
|
|
for i, name := range expectedLevelNames {
|
|
if LevelNames[i] != name {
|
|
t.Errorf("LevelNames[%d] = %s, want %s", i, LevelNames[i], name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetLogLevel(t *testing.T) {
|
|
tests := []struct {
|
|
level string
|
|
expected int
|
|
}{
|
|
{"off", Off},
|
|
{"fatal", Fatal},
|
|
{"error", Error},
|
|
{"warn", Warn},
|
|
{"info", Info},
|
|
{"debug", Debug},
|
|
{"trace", Trace},
|
|
{"unknown", Info}, // Default to Info for unknown levels
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.level, func(t *testing.T) {
|
|
result := GetLogLevel(test.level)
|
|
if result != test.expected {
|
|
t.Errorf("GetLogLevel(%q) = %d, want %d", test.level, result, test.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSetLogLevel(t *testing.T) {
|
|
// Save original level
|
|
originalLevel := Level.Load()
|
|
defer SetLoggers(int(originalLevel)) // Restore original level after test
|
|
|
|
tests := []struct {
|
|
level string
|
|
expected int32
|
|
}{
|
|
{"off", Off},
|
|
{"fatal", Fatal},
|
|
{"error", Error},
|
|
{"warn", Warn},
|
|
{"info", Info},
|
|
{"debug", Debug},
|
|
{"trace", Trace},
|
|
{"unknown", Trace}, // Should default to Trace for unknown levels
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.level, func(t *testing.T) {
|
|
SetLogLevel(test.level)
|
|
result := Level.Load()
|
|
if result != test.expected {
|
|
t.Errorf("After SetLogLevel(%q), Level = %d, want %d", test.level, result, test.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestJoinStrings(t *testing.T) {
|
|
tests := []struct {
|
|
args []any
|
|
expected string
|
|
}{
|
|
{[]any{}, ""},
|
|
{[]any{"hello"}, "hello"},
|
|
{[]any{"hello", "world"}, "hello world"},
|
|
{[]any{1, 2, 3}, "1 2 3"},
|
|
{[]any{1, "hello", 3.14}, "1 hello 3.14"},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
|
|
result := JoinStrings(test.args...)
|
|
if result != test.expected {
|
|
t.Errorf("JoinStrings(%v) = %q, want %q", test.args, result, test.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTimeStamper(t *testing.T) {
|
|
// Test with NoTimeStamp = false
|
|
NoTimeStamp.Store(false)
|
|
timestamp := TimeStamper()
|
|
if timestamp == "" {
|
|
t.Error("TimeStamper() returned empty string when NoTimeStamp = false")
|
|
}
|
|
|
|
// Check format (should be like "2006-01-02T15:04:05Z07:00.000 ")
|
|
_, err := time.Parse("2006-01-02T15:04:05Z07:00.000 ", timestamp)
|
|
if err != nil {
|
|
t.Errorf("TimeStamper() returned timestamp in unexpected format: %q, error: %v", timestamp, err)
|
|
}
|
|
|
|
// Test with NoTimeStamp = true
|
|
NoTimeStamp.Store(true)
|
|
timestamp = TimeStamper()
|
|
if timestamp != "" {
|
|
t.Errorf("TimeStamper() returned %q when NoTimeStamp = true, expected empty string", timestamp)
|
|
}
|
|
|
|
// Reset for other tests
|
|
NoTimeStamp.Store(false)
|
|
}
|
|
|
|
func TestGetLoc(t *testing.T) {
|
|
// Test with ShortLoc = false
|
|
ShortLoc.Store(false)
|
|
loc := GetLoc(1)
|
|
if !strings.Contains(loc, "log_test.go") {
|
|
t.Errorf("GetLoc(1) = %q, expected to contain 'log_test.go'", loc)
|
|
}
|
|
|
|
// Test with ShortLoc = true
|
|
ShortLoc.Store(true)
|
|
loc = GetLoc(1)
|
|
if !strings.Contains(loc, "log_test.go") {
|
|
t.Errorf("GetLoc(1) = %q, expected to contain 'log_test.go'", loc)
|
|
}
|
|
|
|
// Test edge case where file path doesn't contain prefix
|
|
originalPrefix := prefix
|
|
defer func() { prefix = originalPrefix }() // Restore original prefix after test
|
|
|
|
prefix = "non-existent-path"
|
|
loc = GetLoc(1)
|
|
if !strings.Contains(loc, "log_test.go") {
|
|
t.Errorf("GetLoc(1) with non-existent prefix = %q, expected to contain 'log_test.go'", loc)
|
|
}
|
|
|
|
// Reset for other tests
|
|
ShortLoc.Store(false)
|
|
}
|
|
|
|
func TestGetPrinter(t *testing.T) {
|
|
// Create a buffer to capture output
|
|
var buf bytes.Buffer
|
|
|
|
// Set log level to Info
|
|
originalLevel := Level.Load()
|
|
Level.Store(int32(Info))
|
|
defer Level.Store(originalLevel) // Restore original level
|
|
|
|
// Create a printer for Debug level
|
|
printer := GetPrinter(int32(Debug), &buf, 1)
|
|
|
|
// Test Ln method - should not print because Debug > Info
|
|
buf.Reset()
|
|
printer.Ln("test message")
|
|
if buf.String() != "" {
|
|
t.Errorf("printer.Ln() printed when level is too high: %q", buf.String())
|
|
}
|
|
|
|
// Set log level to Debug
|
|
Level.Store(int32(Debug))
|
|
|
|
// Test Ln method - should print now
|
|
buf.Reset()
|
|
printer.Ln("test message")
|
|
output := buf.String()
|
|
if output == "" {
|
|
t.Error("printer.Ln() did not print when it should have")
|
|
}
|
|
if !strings.Contains(output, "test message") {
|
|
t.Errorf("printer.Ln() output %q does not contain 'test message'", output)
|
|
}
|
|
|
|
// Test F method
|
|
buf.Reset()
|
|
printer.F("formatted %s", "message")
|
|
output = buf.String()
|
|
if !strings.Contains(output, "formatted message") {
|
|
t.Errorf("printer.F() output %q does not contain 'formatted message'", output)
|
|
}
|
|
|
|
// Test S method
|
|
buf.Reset()
|
|
printer.S("spew message")
|
|
output = buf.String()
|
|
if !strings.Contains(output, "spew message") {
|
|
t.Errorf("printer.S() output %q does not contain 'spew message'", output)
|
|
}
|
|
|
|
// Test C method
|
|
buf.Reset()
|
|
printer.C(func() string { return "closure message" })
|
|
output = buf.String()
|
|
if !strings.Contains(output, "closure message") {
|
|
t.Errorf("printer.C() output %q does not contain 'closure message'", output)
|
|
}
|
|
|
|
// Test Chk method with nil error
|
|
buf.Reset()
|
|
result := printer.Chk(nil)
|
|
if result != false {
|
|
t.Error("printer.Chk(nil) returned true, expected false")
|
|
}
|
|
if buf.String() != "" {
|
|
t.Errorf("printer.Chk(nil) printed output: %q", buf.String())
|
|
}
|
|
|
|
// Test Chk method with error
|
|
buf.Reset()
|
|
testErr := errors.New("test error")
|
|
result = printer.Chk(testErr)
|
|
if result != true {
|
|
t.Error("printer.Chk(error) returned false, expected true")
|
|
}
|
|
if !strings.Contains(buf.String(), "test error") {
|
|
t.Errorf("printer.Chk(error) output %q does not contain 'test error'", buf.String())
|
|
}
|
|
|
|
// Test Err method
|
|
buf.Reset()
|
|
err := printer.Err("error %s", "message")
|
|
if err == nil {
|
|
t.Error("printer.Err() returned nil error")
|
|
}
|
|
if err.Error() != "error message" {
|
|
t.Errorf("printer.Err() returned error with message %q, expected 'error message'", err.Error())
|
|
}
|
|
// Check if the message was logged
|
|
if !strings.Contains(buf.String(), "error message") {
|
|
t.Errorf("printer.Err() output %q does not contain 'error message'", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestGetNullPrinter(t *testing.T) {
|
|
printer := GetNullPrinter()
|
|
|
|
// Test that Ln, F, S, C methods don't panic
|
|
printer.Ln("test")
|
|
printer.F("test %s", "format")
|
|
printer.S("test")
|
|
printer.C(func() string { return "test" })
|
|
|
|
// Test Chk method
|
|
if !printer.Chk(errors.New("test")) {
|
|
t.Error("GetNullPrinter().Chk(error) returned false, expected true")
|
|
}
|
|
if printer.Chk(nil) {
|
|
t.Error("GetNullPrinter().Chk(nil) returned true, expected false")
|
|
}
|
|
|
|
// Test Err method
|
|
err := printer.Err("test %s", "error")
|
|
if err == nil {
|
|
t.Error("GetNullPrinter().Err() returned nil error")
|
|
}
|
|
if err.Error() != "test error" {
|
|
t.Errorf("GetNullPrinter().Err() returned error with message %q, expected 'test error'", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
log, check, errorf := New(&buf, 1)
|
|
|
|
// Verify that all components are created
|
|
if log == nil {
|
|
t.Error("New() returned nil Log")
|
|
}
|
|
if check == nil {
|
|
t.Error("New() returned nil Check")
|
|
}
|
|
if errorf == nil {
|
|
t.Error("New() returned nil Errorf")
|
|
}
|
|
|
|
// Test that the log functions work
|
|
originalLevel := Level.Load()
|
|
Level.Store(int32(Debug))
|
|
defer Level.Store(originalLevel)
|
|
|
|
buf.Reset()
|
|
log.D.Ln("test message")
|
|
if !strings.Contains(buf.String(), "test message") {
|
|
t.Errorf("log.D.Ln() output %q does not contain 'test message'", buf.String())
|
|
}
|
|
}
|