File size: 6,213 Bytes
6d60378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package main

import (
	"bytes"
	"reflect"
	"strings"
	"testing"
)

// TestParseRealmArgs 覆盖 --realm 参数解析:缺省 cn、等号/分离式写法、
// 非法值/缺值报错、大小写归一、剥离 flag 后剩余参数保持相对顺序。
func TestParseRealmArgs(t *testing.T) {
	cases := []struct {
		name      string
		args      []string
		wantRealm string
		wantRest  []string
		wantErr   bool
	}{
		{name: "缺省 cn", args: []string{"url"}, wantRealm: "cn", wantRest: []string{"url"}},
		{name: "等号 global 在前", args: []string{"--realm=global", "url"}, wantRealm: "global", wantRest: []string{"url"}},
		{name: "等号 cn 在后", args: []string{"poll", "--realm=cn"}, wantRealm: "cn", wantRest: []string{"poll"}},
		{name: "分离式 global", args: []string{"--realm", "global", "url"}, wantRealm: "global", wantRest: []string{"url"}},
		{name: "非法值报错", args: []string{"--realm=foo", "url"}, wantErr: true},
		{name: "分离式缺值报错", args: []string{"--realm", "url"}, wantErr: true},
		{name: "大小写归一", args: []string{"--realm=GLOBAL", "url"}, wantRealm: "global", wantRest: []string{"url"}},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			realm, rest, err := parseRealmArgs(c.args)
			if c.wantErr {
				if err == nil {
					t.Fatalf("parseRealmArgs(%v) err=nil, want error", c.args)
				}
				return
			}
			if err != nil {
				t.Fatalf("parseRealmArgs(%v) err=%v", c.args, err)
			}
			if realm != c.wantRealm {
				t.Errorf("realm=%q want %q", realm, c.wantRealm)
			}
			if !reflect.DeepEqual(rest, c.wantRest) {
				t.Errorf("rest=%v want %v", rest, c.wantRest)
			}
		})
	}
}

// TestResolveRealmInput 覆盖交互式选域的输入→realm 映射(login.sh 交互分支的核心决策):
// "1"/"cn"/""(回车默认)→ cn;"2"/"global" → global;大小写不敏感;非法 → ("",false)。
func TestResolveRealmInput(t *testing.T) {
	cases := []struct {
		input string
		want  string
	}{
		{input: "1", want: "cn"},
		{input: "cn", want: "cn"},
		{input: "CN", want: "cn"},
		{input: "", want: "cn"}, // 回车默认
		{input: "2", want: "global"},
		{input: "global", want: "global"},
		{input: "GLOBAL", want: "global"},
	}
	for _, c := range cases {
		got, ok := resolveRealmInput(c.input)
		if !ok {
			t.Errorf("resolveRealmInput(%q) ok=false want true", c.input)
			continue
		}
		if got != c.want {
			t.Errorf("resolveRealmInput(%q)=%q want %q", c.input, got, c.want)
		}
	}
	// 非法输入 → (false)。
	for _, bad := range []string{"3", "cnn", "globalx", "foo"} {
		if got, ok := resolveRealmInput(bad); ok {
			t.Errorf("resolveRealmInput(%q)=(%q,true) want (_,false)", bad, got)
		}
	}
}

// TestPromptRealm 覆盖 promptRealm 的 I/O 行为(out 将接 os.Stderr,stdout 只出 realm):
//
//	1 / 2 / 回车默认 → 分别输出来 cn / global / cn;均打印"选择登录版本"提示;
//	非法输入 → 警告并回落 cn;EOF(非交互直接管道)→ 回落 cn。
func TestPromptRealm(t *testing.T) {
	cases := []struct {
		name     string
		input    string
		want     string
		wantHint bool // 输出中出现"选择登录版本"提示
	}{
		{name: "选 cn", input: "1\n", want: "cn", wantHint: true},
		{name: "选 global", input: "2\n", want: "global", wantHint: true},
		{name: "回车默认 cn", input: "\n", want: "cn", wantHint: true},
		{name: "非法回落 cn", input: "foo\n", want: "cn", wantHint: true},
		{name: "EOF 回落 cn", input: "", want: "cn", wantHint: true},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			var out bytes.Buffer
			got := promptRealm(strings.NewReader(c.input), &out)
			if got != c.want {
				t.Errorf("promptRealm(%q)=%q want %q", c.input, got, c.want)
			}
			if c.wantHint && !strings.Contains(out.String(), "选择登录版本") {
				t.Errorf("prompt should contain '选择登录版本', got %q", out.String())
			}
		})
	}
}

// TestRealmSubcommandSelection 通过命令形式验证 realm 子命令(login.sh 交互分支调用):
// 子命令剥离 --realm,剩余参数为首个 "realm"。
func TestRealmSubcommandSelection(t *testing.T) {
	realm, rest, err := parseRealmArgs([]string{"realm"})
	if err != nil {
		t.Fatalf("parseRealmArgs(realm) err=%v", err)
	}
	if realm != "cn" {
		t.Errorf("realm default=%q want cn", realm)
	}
	if len(rest) != 1 || rest[0] != "realm" {
		t.Errorf("rest=%v want [realm]", rest)
	}
}

// TestBuildLoginOutputRealmAlwaysSet 登录产物(login.sh 据此落盘 auth 文件)恒含 realm 键:
// 显式 --realm 优先,缺省时按 domain 推断(echo 出的 global 账号即便未显式指定也带 global)。
// 这是「登录落盘永远带 realm 标识」契约的测试载体。
func TestBuildLoginOutputRealmAlwaysSet(t *testing.T) {
	tok := struct {
		AccessToken  string `json:"accessToken"`
		RefreshToken string `json:"refreshToken"`
		ExpiresIn    int64  `json:"expiresIn"`
		Domain       string `json:"domain"`
	}{AccessToken: "at", RefreshToken: "rt", ExpiresIn: 3600, Domain: "www.codebuddy.cn"}
	acct := struct {
		UID          string `json:"uid"`
		EnterpriseID string `json:"enterpriseId"`
		Nickname     string `json:"nickname"`
	}{UID: "u1", Nickname: "n1"}

	cases := []struct {
		name      string
		realm     string
		domain    string
		wantRealm string
	}{
		{name: "显式 global 优先", realm: "global", domain: "www.codebuddy.cn", wantRealm: "global"},
		{name: "显式 cn 优先", realm: "cn", domain: "www.workbuddy.ai", wantRealm: "cn"},
		{name: "缺省按 domain 推断 global", realm: "", domain: "www.workbuddy.ai", wantRealm: "global"},
		{name: "缺省空 domain 回落 cn", realm: "", domain: "", wantRealm: "cn"},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			tok.Domain = c.domain
			out := buildLoginOutput(tok, c.realm, acct)
			m, ok := out["realm"].(string)
			if !ok {
				t.Fatalf("missing realm key in login output: %v", out)
			}
			if m != c.wantRealm {
				t.Errorf("realm=%q want %q", m, c.wantRealm)
			}
		})
	}
}