254 lines
6.7 KiB
Go
254 lines
6.7 KiB
Go
package keyvalue
|
|
|
|
import (
|
|
"bytes"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestStruct is a test struct with various field types and env tags
|
|
type TestStruct struct {
|
|
StringField string `env:"STRING_FIELD"`
|
|
IntField int `env:"INT_FIELD"`
|
|
BoolField bool `env:"BOOL_FIELD"`
|
|
DurationField time.Duration `env:"DURATION_FIELD"`
|
|
StringSlice []string `env:"STRING_SLICE"`
|
|
EmptySlice []string `env:"EMPTY_SLICE"`
|
|
NoTagField string // Field without env tag
|
|
EmbeddedStruct struct{} // Embedded struct
|
|
}
|
|
|
|
// EmbeddedTestStruct is a test struct with an embedded struct
|
|
type EmbeddedTestStruct struct {
|
|
TestStruct
|
|
AdditionalField string `env:"ADDITIONAL_FIELD"`
|
|
}
|
|
|
|
func TestEnvKV(t *testing.T) {
|
|
// Test case 1: Basic struct with various field types
|
|
testStruct := TestStruct{
|
|
StringField: "test-string",
|
|
IntField: 42,
|
|
BoolField: true,
|
|
DurationField: 5 * time.Second,
|
|
StringSlice: []string{"one", "two", "three"},
|
|
EmptySlice: []string{},
|
|
NoTagField: "no-tag",
|
|
}
|
|
|
|
kvs := EnvKV(testStruct)
|
|
|
|
// Expected key-value pairs
|
|
expected := KVSlice{
|
|
{Key: "STRING_FIELD", Value: "test-string"},
|
|
{Key: "INT_FIELD", Value: "42"},
|
|
{Key: "BOOL_FIELD", Value: "true"},
|
|
{Key: "DURATION_FIELD", Value: "5s"},
|
|
{Key: "STRING_SLICE", Value: "one,two,three"},
|
|
{Key: "EMPTY_SLICE", Value: ""},
|
|
}
|
|
|
|
// Check if the number of key-value pairs is correct
|
|
if len(kvs) != len(expected) {
|
|
t.Errorf("Expected %d key-value pairs, got %d", len(expected), len(kvs))
|
|
}
|
|
|
|
// Create a map for easier comparison
|
|
kvMap := make(map[string]string)
|
|
for _, kv := range kvs {
|
|
kvMap[kv.Key] = kv.Value
|
|
}
|
|
|
|
// Check if all expected key-value pairs are present
|
|
for _, kv := range expected {
|
|
if val, ok := kvMap[kv.Key]; !ok || val != kv.Value {
|
|
t.Errorf("Expected key %s with value %s, got %s", kv.Key, kv.Value, val)
|
|
}
|
|
}
|
|
|
|
// Test case 2: Struct with embedded struct
|
|
embeddedStruct := EmbeddedTestStruct{
|
|
TestStruct: TestStruct{
|
|
StringField: "embedded-string",
|
|
IntField: 100,
|
|
},
|
|
AdditionalField: "additional",
|
|
}
|
|
|
|
embeddedKVs := EnvKV(embeddedStruct)
|
|
|
|
// Check if the additional field is present
|
|
found := false
|
|
for _, kv := range embeddedKVs {
|
|
if kv.Key == "ADDITIONAL_FIELD" && kv.Value == "additional" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("Expected to find ADDITIONAL_FIELD with value 'additional' in embedded struct")
|
|
}
|
|
|
|
// Test case 3: Pointer to a struct
|
|
pointerStruct := &TestStruct{
|
|
StringField: "pointer-string",
|
|
IntField: 123,
|
|
BoolField: false,
|
|
DurationField: 10 * time.Second,
|
|
StringSlice: []string{"four", "five", "six"},
|
|
}
|
|
|
|
pointerKVs := EnvKV(pointerStruct)
|
|
|
|
// Expected key-value pairs for pointer struct
|
|
expectedPointer := KVSlice{
|
|
{Key: "STRING_FIELD", Value: "pointer-string"},
|
|
{Key: "INT_FIELD", Value: "123"},
|
|
{Key: "BOOL_FIELD", Value: "false"},
|
|
{Key: "DURATION_FIELD", Value: "10s"},
|
|
{Key: "STRING_SLICE", Value: "four,five,six"},
|
|
{Key: "EMPTY_SLICE", Value: ""},
|
|
}
|
|
|
|
// Check if the number of key-value pairs is correct
|
|
if len(pointerKVs) != len(expectedPointer) {
|
|
t.Errorf("Expected %d key-value pairs for pointer struct, got %d", len(expectedPointer), len(pointerKVs))
|
|
}
|
|
|
|
// Create a map for easier comparison
|
|
pointerKVMap := make(map[string]string)
|
|
for _, kv := range pointerKVs {
|
|
pointerKVMap[kv.Key] = kv.Value
|
|
}
|
|
|
|
// Check if all expected key-value pairs are present
|
|
for _, kv := range expectedPointer {
|
|
if val, ok := pointerKVMap[kv.Key]; !ok || val != kv.Value {
|
|
t.Errorf("Expected key %s with value %s for pointer struct, got %s", kv.Key, kv.Value, val)
|
|
}
|
|
}
|
|
|
|
// Test case 4: Nil pointer
|
|
var nilPointer *TestStruct = nil
|
|
nilKVs := EnvKV(nilPointer)
|
|
|
|
// Nil pointer should return empty slice
|
|
if len(nilKVs) != 0 {
|
|
t.Errorf("Expected empty slice for nil pointer, got %d items", len(nilKVs))
|
|
}
|
|
}
|
|
|
|
func TestPrintEnv(t *testing.T) {
|
|
// Test case 1: Regular struct
|
|
testStruct := TestStruct{
|
|
StringField: "test-string",
|
|
IntField: 42,
|
|
BoolField: true,
|
|
DurationField: 5 * time.Second,
|
|
StringSlice: []string{"one", "two", "three"},
|
|
}
|
|
|
|
// Create a buffer to capture the output
|
|
var buf bytes.Buffer
|
|
|
|
// Call PrintEnv
|
|
PrintEnv(testStruct, &buf)
|
|
|
|
// Get the output as a string
|
|
output := buf.String()
|
|
|
|
// Expected output (note: keys should be sorted)
|
|
expected := "#!/usr/bin/env bash\n" +
|
|
"export BOOL_FIELD=true\n" +
|
|
"export DURATION_FIELD=5s\n" +
|
|
"export EMPTY_SLICE=\n" +
|
|
"export INT_FIELD=42\n" +
|
|
"export STRING_FIELD=test-string\n" +
|
|
"export STRING_SLICE=one,two,three\n"
|
|
|
|
if output != expected {
|
|
t.Errorf("PrintEnv output does not match expected.\nExpected:\n%s\nGot:\n%s", expected, output)
|
|
}
|
|
|
|
// Test case 2: Pointer to struct
|
|
pointerStruct := &TestStruct{
|
|
StringField: "pointer-string",
|
|
IntField: 123,
|
|
BoolField: false,
|
|
DurationField: 10 * time.Second,
|
|
StringSlice: []string{"four", "five", "six"},
|
|
}
|
|
|
|
// Create a new buffer for the pointer test
|
|
var pointerBuf bytes.Buffer
|
|
|
|
// Call PrintEnv with a pointer
|
|
PrintEnv(pointerStruct, &pointerBuf)
|
|
|
|
// Get the output as a string
|
|
pointerOutput := pointerBuf.String()
|
|
|
|
// Expected output for pointer struct
|
|
expectedPointer := "#!/usr/bin/env bash\n" +
|
|
"export BOOL_FIELD=false\n" +
|
|
"export DURATION_FIELD=10s\n" +
|
|
"export EMPTY_SLICE=\n" +
|
|
"export INT_FIELD=123\n" +
|
|
"export STRING_FIELD=pointer-string\n" +
|
|
"export STRING_SLICE=four,five,six\n"
|
|
|
|
if pointerOutput != expectedPointer {
|
|
t.Errorf("PrintEnv output for pointer struct does not match expected.\nExpected:\n%s\nGot:\n%s",
|
|
expectedPointer, pointerOutput)
|
|
}
|
|
|
|
// Test case 3: Nil pointer
|
|
var nilPointer *TestStruct = nil
|
|
var nilBuf bytes.Buffer
|
|
|
|
// Call PrintEnv with a nil pointer
|
|
PrintEnv(nilPointer, &nilBuf)
|
|
|
|
// Get the output as a string
|
|
nilOutput := nilBuf.String()
|
|
|
|
// Expected output for nil pointer (just the shebang line)
|
|
expectedNil := "#!/usr/bin/env bash\n"
|
|
|
|
if nilOutput != expectedNil {
|
|
t.Errorf("PrintEnv output for nil pointer does not match expected.\nExpected:\n%s\nGot:\n%s",
|
|
expectedNil, nilOutput)
|
|
}
|
|
}
|
|
|
|
func TestKVSliceSorting(t *testing.T) {
|
|
// Create an unsorted KVSlice
|
|
kvs := KVSlice{
|
|
{Key: "C", Value: "3"},
|
|
{Key: "A", Value: "1"},
|
|
{Key: "B", Value: "2"},
|
|
}
|
|
|
|
// Expected sorted KVSlice
|
|
expected := KVSlice{
|
|
{Key: "A", Value: "1"},
|
|
{Key: "B", Value: "2"},
|
|
{Key: "C", Value: "3"},
|
|
}
|
|
|
|
// Sort the KVSlice
|
|
kvsCopy := make(KVSlice, len(kvs))
|
|
copy(kvsCopy, kvs)
|
|
reflect.DeepEqual(kvs, kvsCopy) // Verify the copy worked
|
|
|
|
// Sort the copy
|
|
sort.Sort(kvsCopy)
|
|
|
|
// Check if the sorted KVSlice matches the expected
|
|
if !reflect.DeepEqual(kvsCopy, expected) {
|
|
t.Errorf("KVSlice sorting failed. Expected %v, got %v", expected, kvsCopy)
|
|
}
|
|
}
|