test all keyvalue and fix bugs
This commit is contained in:
@@ -23,21 +23,30 @@ func (kv KVSlice) Less(i, j int) bool { return kv[i].Key < kv[j].Key }
|
|||||||
func (kv KVSlice) Swap(i, j int) { kv[i], kv[j] = kv[j], kv[i] }
|
func (kv KVSlice) Swap(i, j int) { kv[i], kv[j] = kv[j], kv[i] }
|
||||||
|
|
||||||
// EnvKV turns a struct with `env` keys (used with go-simpler/env) into a standard formatted
|
// EnvKV turns a struct with `env` keys (used with go-simpler/env) into a standard formatted
|
||||||
// environment variable key/value pair list, one per line. Note you must dereference a pointer
|
// environment variable key/value pair list, one per line. If a pointer to a struct is passed,
|
||||||
// type to use this. This allows the composition of the config in this file with an extended
|
// it will be automatically dereferenced. This allows the composition of the config in this file
|
||||||
// form with a customized variant of realy to produce correct environment variables both read
|
// with an extended form with a customized variant of realy to produce correct environment
|
||||||
// and write.
|
// variables both read and write.
|
||||||
func EnvKV(cfg any) (m KVSlice) {
|
func EnvKV(cfg any) (m KVSlice) {
|
||||||
t := reflect.TypeOf(cfg)
|
// Handle pointer types by dereferencing them
|
||||||
|
v := reflect.ValueOf(cfg)
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() {
|
||||||
|
return // Return empty slice for nil pointers
|
||||||
|
}
|
||||||
|
return EnvKV(v.Elem().Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
t := v.Type()
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
k := t.Field(i).Tag.Get("env")
|
k := t.Field(i).Tag.Get("env")
|
||||||
v := reflect.ValueOf(cfg).Field(i).Interface()
|
fieldValue := v.Field(i).Interface()
|
||||||
var val string
|
var val string
|
||||||
switch u := v.(type) {
|
switch u := fieldValue.(type) {
|
||||||
case string:
|
case string:
|
||||||
val = u
|
val = u
|
||||||
case int, int64, int32, uint64, uint32, bool, time.Duration:
|
case int, int64, int32, uint64, uint32, bool, time.Duration:
|
||||||
val = fmt.Sprint(v)
|
val = fmt.Sprint(fieldValue)
|
||||||
case []string:
|
case []string:
|
||||||
if len(u) > 0 {
|
if len(u) > 0 {
|
||||||
val = strings.Join(u, ",")
|
val = strings.Join(u, ",")
|
||||||
@@ -52,7 +61,8 @@ func EnvKV(cfg any) (m KVSlice) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintEnv renders the key/values of a config.C to a provided io.Writer.
|
// PrintEnv renders the key/values of a config struct to a provided io.Writer.
|
||||||
|
// If a pointer to a struct is passed, it will be automatically dereferenced.
|
||||||
func PrintEnv(cfg any, printer io.Writer) {
|
func PrintEnv(cfg any, printer io.Writer) {
|
||||||
_, _ = fmt.Fprintln(printer, "#!/usr/bin/env bash")
|
_, _ = fmt.Fprintln(printer, "#!/usr/bin/env bash")
|
||||||
kvs := EnvKV(cfg)
|
kvs := EnvKV(cfg)
|
||||||
|
|||||||
@@ -90,10 +90,58 @@ func TestEnvKV(t *testing.T) {
|
|||||||
if !found {
|
if !found {
|
||||||
t.Errorf("Expected to find ADDITIONAL_FIELD with value 'additional' in embedded struct")
|
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) {
|
func TestPrintEnv(t *testing.T) {
|
||||||
// Create a test struct
|
// Test case 1: Regular struct
|
||||||
testStruct := TestStruct{
|
testStruct := TestStruct{
|
||||||
StringField: "test-string",
|
StringField: "test-string",
|
||||||
IntField: 42,
|
IntField: 42,
|
||||||
@@ -123,6 +171,56 @@ func TestPrintEnv(t *testing.T) {
|
|||||||
if output != expected {
|
if output != expected {
|
||||||
t.Errorf("PrintEnv output does not match expected.\nExpected:\n%s\nGot:\n%s", expected, output)
|
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) {
|
func TestKVSliceSorting(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user