1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-12-19 23:42:05 +02:00
Files
fp-go/v2/either/format_test.go
Dr. Carsten Leue 255cf4353c fix: better formatting
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-12-18 16:07:26 +01:00

312 lines
8.2 KiB
Go

// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package either
import (
"bytes"
"errors"
"fmt"
"log/slog"
"testing"
"github.com/stretchr/testify/assert"
)
func TestString(t *testing.T) {
t.Run("Right value", func(t *testing.T) {
e := Right[error](42)
result := e.String()
assert.Equal(t, "Right[int](42)", result)
})
t.Run("Left value", func(t *testing.T) {
e := Left[int](errors.New("test error"))
result := e.String()
assert.Contains(t, result, "Left[*errors.errorString]")
assert.Contains(t, result, "test error")
})
t.Run("Right with string", func(t *testing.T) {
e := Right[error]("hello")
result := e.String()
assert.Equal(t, "Right[string](hello)", result)
})
t.Run("Left with string", func(t *testing.T) {
e := Left[int]("error message")
result := e.String()
assert.Equal(t, "Left[string](error message)", result)
})
}
func TestGoString(t *testing.T) {
t.Run("Right value", func(t *testing.T) {
e := Right[error](42)
result := e.GoString()
assert.Contains(t, result, "either.Right")
assert.Contains(t, result, "42")
})
t.Run("Left value", func(t *testing.T) {
e := Left[int](errors.New("test error"))
result := e.GoString()
assert.Contains(t, result, "either.Left")
assert.Contains(t, result, "test error")
})
t.Run("Right with struct", func(t *testing.T) {
type TestStruct struct {
Name string
Age int
}
e := Right[error](TestStruct{Name: "Alice", Age: 30})
result := e.GoString()
assert.Contains(t, result, "either.Right")
assert.Contains(t, result, "Alice")
assert.Contains(t, result, "30")
})
t.Run("Left with custom error", func(t *testing.T) {
e := Left[string]("custom error")
result := e.GoString()
assert.Contains(t, result, "either.Left")
assert.Contains(t, result, "custom error")
})
}
func TestFormatInterface(t *testing.T) {
t.Run("Right value with %s", func(t *testing.T) {
e := Right[error](42)
result := fmt.Sprintf("%s", e)
assert.Equal(t, "Right[int](42)", result)
})
t.Run("Left value with %s", func(t *testing.T) {
e := Left[int](errors.New("test error"))
result := fmt.Sprintf("%s", e)
assert.Contains(t, result, "Left")
assert.Contains(t, result, "test error")
})
t.Run("Right value with %v", func(t *testing.T) {
e := Right[error](42)
result := fmt.Sprintf("%v", e)
assert.Equal(t, "Right[int](42)", result)
})
t.Run("Left value with %v", func(t *testing.T) {
e := Left[int]("error")
result := fmt.Sprintf("%v", e)
assert.Equal(t, "Left[string](error)", result)
})
t.Run("Right value with %+v", func(t *testing.T) {
e := Right[error](42)
result := fmt.Sprintf("%+v", e)
assert.Contains(t, result, "Right")
assert.Contains(t, result, "42")
})
t.Run("Right value with %#v (GoString)", func(t *testing.T) {
e := Right[error](42)
result := fmt.Sprintf("%#v", e)
assert.Contains(t, result, "either.Right")
assert.Contains(t, result, "42")
})
t.Run("Left value with %#v (GoString)", func(t *testing.T) {
e := Left[int]("error")
result := fmt.Sprintf("%#v", e)
assert.Contains(t, result, "either.Left")
assert.Contains(t, result, "error")
})
t.Run("Right value with %q", func(t *testing.T) {
e := Right[error]("hello")
result := fmt.Sprintf("%q", e)
// Should use String() representation
assert.Contains(t, result, "Right")
})
t.Run("Right value with %T", func(t *testing.T) {
e := Right[error](42)
result := fmt.Sprintf("%T", e)
assert.Contains(t, result, "either.Either")
})
}
func TestLogValue(t *testing.T) {
t.Run("Right value", func(t *testing.T) {
e := Right[error](42)
logValue := e.LogValue()
// Should be a group value
assert.Equal(t, slog.KindGroup, logValue.Kind())
// Extract the group attributes
attrs := logValue.Group()
assert.Len(t, attrs, 1)
assert.Equal(t, "right", attrs[0].Key)
assert.Equal(t, int64(42), attrs[0].Value.Any())
})
t.Run("Left value", func(t *testing.T) {
e := Left[int](errors.New("test error"))
logValue := e.LogValue()
// Should be a group value
assert.Equal(t, slog.KindGroup, logValue.Kind())
// Extract the group attributes
attrs := logValue.Group()
assert.Len(t, attrs, 1)
assert.Equal(t, "left", attrs[0].Key)
assert.NotNil(t, attrs[0].Value.Any())
})
t.Run("Right with string", func(t *testing.T) {
e := Right[error]("success")
logValue := e.LogValue()
// Should be a group value
assert.Equal(t, slog.KindGroup, logValue.Kind())
// Extract the group attributes
attrs := logValue.Group()
assert.Len(t, attrs, 1)
assert.Equal(t, "right", attrs[0].Key)
assert.Equal(t, "success", attrs[0].Value.Any())
})
t.Run("Left with string", func(t *testing.T) {
e := Left[int]("error message")
logValue := e.LogValue()
// Should be a group value
assert.Equal(t, slog.KindGroup, logValue.Kind())
// Extract the group attributes
attrs := logValue.Group()
assert.Len(t, attrs, 1)
assert.Equal(t, "left", attrs[0].Key)
assert.Equal(t, "error message", attrs[0].Value.Any())
})
t.Run("Integration with slog - Right", func(t *testing.T) {
var buf bytes.Buffer
logger := slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
e := Right[error](42)
logger.Info("test message", "result", e)
output := buf.String()
assert.Contains(t, output, "test message")
assert.Contains(t, output, "result")
assert.Contains(t, output, "right")
assert.Contains(t, output, "42")
})
t.Run("Integration with slog - Left", func(t *testing.T) {
var buf bytes.Buffer
logger := slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
e := Left[int]("error occurred")
logger.Info("test message", "result", e)
output := buf.String()
assert.Contains(t, output, "test message")
assert.Contains(t, output, "result")
assert.Contains(t, output, "left")
assert.Contains(t, output, "error occurred")
})
}
func TestFormatComprehensive(t *testing.T) {
t.Run("All format verbs for Right", func(t *testing.T) {
e := Right[error](42)
tests := []struct {
verb string
contains []string
}{
{"%s", []string{"Right", "42"}},
{"%v", []string{"Right", "42"}},
{"%+v", []string{"Right", "42"}},
{"%#v", []string{"either.Right", "42"}},
{"%T", []string{"either.Either"}},
}
for _, tt := range tests {
t.Run(tt.verb, func(t *testing.T) {
result := fmt.Sprintf(tt.verb, e)
for _, substr := range tt.contains {
assert.Contains(t, result, substr, "Format %s should contain %s", tt.verb, substr)
}
})
}
})
t.Run("All format verbs for Left", func(t *testing.T) {
e := Left[int]("error")
tests := []struct {
verb string
contains []string
}{
{"%s", []string{"Left", "error"}},
{"%v", []string{"Left", "error"}},
{"%+v", []string{"Left", "error"}},
{"%#v", []string{"either.Left", "error"}},
{"%T", []string{"either.Either"}},
}
for _, tt := range tests {
t.Run(tt.verb, func(t *testing.T) {
result := fmt.Sprintf(tt.verb, e)
for _, substr := range tt.contains {
assert.Contains(t, result, substr, "Format %s should contain %s", tt.verb, substr)
}
})
}
})
}
func TestInterfaceImplementations(t *testing.T) {
t.Run("fmt.Stringer interface", func(t *testing.T) {
var _ fmt.Stringer = Right[error](42)
var _ fmt.Stringer = Left[int](errors.New("error"))
})
t.Run("fmt.GoStringer interface", func(t *testing.T) {
var _ fmt.GoStringer = Right[error](42)
var _ fmt.GoStringer = Left[int](errors.New("error"))
})
t.Run("fmt.Formatter interface", func(t *testing.T) {
var _ fmt.Formatter = Right[error](42)
var _ fmt.Formatter = Left[int](errors.New("error"))
})
t.Run("slog.LogValuer interface", func(t *testing.T) {
var _ slog.LogValuer = Right[error](42)
var _ slog.LogValuer = Left[int](errors.New("error"))
})
}