package util import ( "context" "reflect" "strings" "testing" "github.com/davecgh/go-spew/spew" "go-micro.dev/v6/metadata" goregistry "go-micro.dev/v6/registry" ) type parseCase struct { args []string values *goregistry.Value expected map[string]interface{} } func TestDynamicFlagParsing(t *testing.T) { cases := []parseCase{ { args: []string{"--ss=a,b"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "ss", Type: "[]string", }, }, }, expected: map[string]interface{}{ "ss": []interface{}{"a", "b"}, }, }, { args: []string{"--ss", "a,b"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "ss", Type: "[]string", }, }, }, expected: map[string]interface{}{ "ss": []interface{}{"a", "b"}, }, }, { args: []string{"--ss=a", "--ss=b"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "ss", Type: "[]string", }, }, }, expected: map[string]interface{}{ "ss": []interface{}{"a", "b"}, }, }, { args: []string{"--ss", "a", "--ss", "b"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "ss", Type: "[]string", }, }, }, expected: map[string]interface{}{ "ss": []interface{}{"a", "b"}, }, }, { args: []string{"--bs=true,false"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "bs", Type: "[]bool", }, }, }, expected: map[string]interface{}{ "bs": []interface{}{true, false}, }, }, { args: []string{"--bs", "true,false"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "bs", Type: "[]bool", }, }, }, expected: map[string]interface{}{ "bs": []interface{}{true, false}, }, }, { args: []string{"--bs=true", "--bs=false"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "bs", Type: "[]bool", }, }, }, expected: map[string]interface{}{ "bs": []interface{}{true, false}, }, }, { args: []string{"--bs", "true", "--bs", "false"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "bs", Type: "[]bool", }, }, }, expected: map[string]interface{}{ "bs": []interface{}{true, false}, }, }, { args: []string{"--is=10,20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int32", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int32(10), int32(20)}, }, }, { args: []string{"--is", "10,20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int32", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int32(10), int32(20)}, }, }, { args: []string{"--is=10", "--is=20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int32", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int32(10), int32(20)}, }, }, { args: []string{"--is", "10", "--is", "20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int32", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int32(10), int32(20)}, }, }, { args: []string{"--is=10,20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int64", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int64(10), int64(20)}, }, }, { args: []string{"--is", "10,20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int64", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int64(10), int64(20)}, }, }, { args: []string{"--is=10", "--is=20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int64", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int64(10), int64(20)}, }, }, { args: []string{"--is", "10", "--is", "20"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "is", Type: "[]int64", }, }, }, expected: map[string]interface{}{ "is": []interface{}{int64(10), int64(20)}, }, }, { args: []string{"--fs=10.1,20.2"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "fs", Type: "[]float64", }, }, }, expected: map[string]interface{}{ "fs": []interface{}{float64(10.1), float64(20.2)}, }, }, { args: []string{"--fs", "10.1,20.2"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "fs", Type: "[]float64", }, }, }, expected: map[string]interface{}{ "fs": []interface{}{float64(10.1), float64(20.2)}, }, }, { args: []string{"--fs=10.1", "--fs=20.2"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "fs", Type: "[]float64", }, }, }, expected: map[string]interface{}{ "fs": []interface{}{float64(10.1), float64(20.2)}, }, }, { args: []string{"--fs", "10.1", "--fs", "20.2"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "fs", Type: "[]float64", }, }, }, expected: map[string]interface{}{ "fs": []interface{}{float64(10.1), float64(20.2)}, }, }, { args: []string{"--user_email=someemail"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "user_email", Type: "string", }, }, }, expected: map[string]interface{}{ "user_email": "someemail", }, }, { args: []string{"--user_email=someemail", "--user_name=somename"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "user_email", Type: "string", }, { Name: "user_name", Type: "string", }, }, }, expected: map[string]interface{}{ "user_email": "someemail", "user_name": "somename", }, }, { args: []string{"--b"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "b", Type: "bool", }, }, }, expected: map[string]interface{}{ "b": true, }, }, { args: []string{"--user_friend_email=hi"}, values: &goregistry.Value{ Values: []*goregistry.Value{ { Name: "user_friend_email", Type: "string", }, }, }, expected: map[string]interface{}{ "user_friend_email": "hi", }, }, } for _, c := range cases { t.Run(strings.Join(c.args, " "), func(t *testing.T) { _, flags, err := splitCmdArgs(c.args) if err != nil { t.Fatal(err) } req, err := FlagsToRequest(flags, c.values) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(c.expected, req) { spew.Dump("Expected:", c.expected, "got: ", req) t.Fatalf("Expected %v, got %v", c.expected, req) } }) } } func TestAddMetadataToContext(t *testing.T) { tests := []struct { name string metadataStrs []string expectedKeys []string expectedValues []string }{ { name: "Single metadata", metadataStrs: []string{"Key1:Value1"}, expectedKeys: []string{"Key1"}, expectedValues: []string{"Value1"}, }, { name: "Multiple metadata", metadataStrs: []string{"Key1:Value1", "Key2:Value2"}, expectedKeys: []string{"Key1", "Key2"}, expectedValues: []string{"Value1", "Value2"}, }, { name: "Metadata with spaces", metadataStrs: []string{"Key1: Value1 ", " Key2 : Value2"}, expectedKeys: []string{"Key1", "Key2"}, expectedValues: []string{"Value1", "Value2"}, }, { name: "Metadata with colon in value", metadataStrs: []string{"Authorization:Bearer token:123"}, expectedKeys: []string{"Authorization"}, expectedValues: []string{"Bearer token:123"}, }, { name: "Empty metadata", metadataStrs: []string{}, expectedKeys: []string{}, expectedValues: []string{}, }, { name: "Invalid metadata format", metadataStrs: []string{"InvalidFormat"}, expectedKeys: []string{}, expectedValues: []string{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() ctx = AddMetadataToContext(ctx, tt.metadataStrs) md, ok := metadata.FromContext(ctx) if len(tt.expectedKeys) == 0 && !ok { return // Expected no metadata } if !ok && len(tt.expectedKeys) > 0 { t.Fatal("Expected metadata in context but got none") } for i, key := range tt.expectedKeys { value, found := md.Get(key) if !found { t.Fatalf("Expected key %s not found in metadata", key) } if value != tt.expectedValues[i] { t.Fatalf("Expected value %s for key %s, got %s", tt.expectedValues[i], key, value) } } }) } }