package ctxext import ( "context" "git.blackforestbytes.com/BlackForestBytes/goext/tst" "testing" ) type ctxKey string const ( keyString ctxKey = "string-key" keyInt ctxKey = "int-key" keyStruct ctxKey = "struct-key" keyPtr ctxKey = "ptr-key" keyMissing ctxKey = "missing-key" ) type sampleStruct struct { Name string N int } func TestValueStringPresent(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "hello") v, ok := Value[string](ctx, keyString) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v, "hello") } func TestValueIntPresent(t *testing.T) { ctx := context.WithValue(context.Background(), keyInt, 42) v, ok := Value[int](ctx, keyInt) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v, 42) } func TestValueStructPresent(t *testing.T) { want := sampleStruct{Name: "abc", N: 7} ctx := context.WithValue(context.Background(), keyStruct, want) v, ok := Value[sampleStruct](ctx, keyStruct) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v.Name, "abc") tst.AssertEqual(t, v.N, 7) } func TestValuePointerPresent(t *testing.T) { want := &sampleStruct{Name: "ptr", N: 99} ctx := context.WithValue(context.Background(), keyPtr, want) v, ok := Value[*sampleStruct](ctx, keyPtr) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v == want, true) tst.AssertEqual(t, v.Name, "ptr") } func TestValueMissing(t *testing.T) { ctx := context.Background() v, ok := Value[string](ctx, keyMissing) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v, "") } func TestValueMissingInt(t *testing.T) { ctx := context.Background() v, ok := Value[int](ctx, keyMissing) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v, 0) } func TestValueMissingStruct(t *testing.T) { ctx := context.Background() v, ok := Value[sampleStruct](ctx, keyMissing) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v.Name, "") tst.AssertEqual(t, v.N, 0) } func TestValueMissingPointer(t *testing.T) { ctx := context.Background() v, ok := Value[*sampleStruct](ctx, keyMissing) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v == nil, true) } func TestValueWrongType(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "hello") v, ok := Value[int](ctx, keyString) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v, 0) } func TestValueWrongTypeStructToString(t *testing.T) { ctx := context.WithValue(context.Background(), keyStruct, sampleStruct{Name: "x"}) v, ok := Value[string](ctx, keyStruct) tst.AssertEqual(t, ok, false) tst.AssertEqual(t, v, "") } func TestValueNilStoredAsInterface(t *testing.T) { var stored *sampleStruct = nil ctx := context.WithValue(context.Background(), keyPtr, stored) v, ok := Value[*sampleStruct](ctx, keyPtr) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v == nil, true) } func TestValueEmptyString(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "") v, ok := Value[string](ctx, keyString) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v, "") } func TestValueZeroInt(t *testing.T) { ctx := context.WithValue(context.Background(), keyInt, 0) v, ok := Value[int](ctx, keyInt) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v, 0) } func TestValueWithStringKey(t *testing.T) { type stringKey string k := stringKey("my-key") ctx := context.WithValue(context.Background(), k, "value") v, ok := Value[string](ctx, k) tst.AssertEqual(t, ok, true) tst.AssertEqual(t, v, "value") } func TestValueOrDefaultPresent(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "hello") v := ValueOrDefault(ctx, keyString, "default") tst.AssertEqual(t, v, "hello") } func TestValueOrDefaultIntPresent(t *testing.T) { ctx := context.WithValue(context.Background(), keyInt, 42) v := ValueOrDefault(ctx, keyInt, -1) tst.AssertEqual(t, v, 42) } func TestValueOrDefaultMissing(t *testing.T) { ctx := context.Background() v := ValueOrDefault(ctx, keyMissing, "default") tst.AssertEqual(t, v, "default") } func TestValueOrDefaultMissingInt(t *testing.T) { ctx := context.Background() v := ValueOrDefault(ctx, keyMissing, 99) tst.AssertEqual(t, v, 99) } func TestValueOrDefaultMissingStruct(t *testing.T) { ctx := context.Background() def := sampleStruct{Name: "default", N: 1} v := ValueOrDefault(ctx, keyMissing, def) tst.AssertEqual(t, v.Name, "default") tst.AssertEqual(t, v.N, 1) } func TestValueOrDefaultWrongType(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "hello") v := ValueOrDefault(ctx, keyString, 7) tst.AssertEqual(t, v, 7) } func TestValueOrDefaultWrongTypeStruct(t *testing.T) { ctx := context.WithValue(context.Background(), keyStruct, sampleStruct{Name: "x"}) def := "fallback" v := ValueOrDefault(ctx, keyStruct, def) tst.AssertEqual(t, v, "fallback") } func TestValueOrDefaultEmptyStringStored(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "") v := ValueOrDefault(ctx, keyString, "default") tst.AssertEqual(t, v, "") } func TestValueOrDefaultZeroIntStored(t *testing.T) { ctx := context.WithValue(context.Background(), keyInt, 0) v := ValueOrDefault(ctx, keyInt, 99) tst.AssertEqual(t, v, 0) } func TestValueOrDefaultPointerPresent(t *testing.T) { want := &sampleStruct{Name: "p", N: 5} ctx := context.WithValue(context.Background(), keyPtr, want) def := &sampleStruct{Name: "def", N: 0} v := ValueOrDefault(ctx, keyPtr, def) tst.AssertEqual(t, v == want, true) } func TestValueOrDefaultPointerMissing(t *testing.T) { ctx := context.Background() def := &sampleStruct{Name: "def", N: 0} v := ValueOrDefault(ctx, keyMissing, def) tst.AssertEqual(t, v == def, true) } func TestValueOrDefaultNilPointerStored(t *testing.T) { var stored *sampleStruct = nil ctx := context.WithValue(context.Background(), keyPtr, stored) def := &sampleStruct{Name: "def"} v := ValueOrDefault(ctx, keyPtr, def) tst.AssertEqual(t, v == nil, true) } func TestValueNestedContext(t *testing.T) { ctx := context.WithValue(context.Background(), keyString, "outer") ctx = context.WithValue(ctx, keyInt, 123) ctx = context.WithValue(ctx, keyString, "inner") vs, oks := Value[string](ctx, keyString) tst.AssertEqual(t, oks, true) tst.AssertEqual(t, vs, "inner") vi, oki := Value[int](ctx, keyInt) tst.AssertEqual(t, oki, true) tst.AssertEqual(t, vi, 123) } func TestValueDifferentKeyTypesDoNotCollide(t *testing.T) { type keyA string type keyB string ctx := context.WithValue(context.Background(), keyA("k"), "a-val") ctx = context.WithValue(ctx, keyB("k"), "b-val") va, oka := Value[string](ctx, keyA("k")) tst.AssertEqual(t, oka, true) tst.AssertEqual(t, va, "a-val") vb, okb := Value[string](ctx, keyB("k")) tst.AssertEqual(t, okb, true) tst.AssertEqual(t, vb, "b-val") }