How to use substituteUsage method of types Package

Best Ginkgo code snippet using types.substituteUsage

Run Ginkgo automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

flags.go

Source: flags.go Github

copy
1package types
2
3import (
4	"flag"
5	"fmt"
6	"io"
7	"reflect"
8	"strings"
9	"time"
10
11	"github.com/onsi/ginkgo/v2/formatter"
12)
13
14type GinkgoFlag struct {
15	Name       string
16	KeyPath    string
17	SectionKey string
18
19	Usage             string
20	UsageArgument     string
21	UsageDefaultValue string
22
23	DeprecatedName    string
24	DeprecatedDocLink string
25	DeprecatedVersion string
26
27	ExportAs string
28}
29
30type GinkgoFlags []GinkgoFlag
31
32func (f GinkgoFlags) CopyAppend(flags ...GinkgoFlag) GinkgoFlags {
33	out := GinkgoFlags{}
34	out = append(out, f...)
35	out = append(out, flags...)
36	return out
37}
38
39func (f GinkgoFlags) WithPrefix(prefix string) GinkgoFlags {
40	if prefix == "" {
41		return f
42	}
43	out := GinkgoFlags{}
44	for _, flag := range f {
45		if flag.Name != "" {
46			flag.Name = prefix + "." + flag.Name
47		}
48		if flag.DeprecatedName != "" {
49			flag.DeprecatedName = prefix + "." + flag.DeprecatedName
50		}
51		if flag.ExportAs != "" {
52			flag.ExportAs = prefix + "." + flag.ExportAs
53		}
54		out = append(out, flag)
55	}
56	return out
57}
58
59func (f GinkgoFlags) SubsetWithNames(names ...string) GinkgoFlags {
60	out := GinkgoFlags{}
61	for _, flag := range f {
62		for _, name := range names {
63			if flag.Name == name {
64				out = append(out, flag)
65				break
66			}
67		}
68	}
69	return out
70}
71
72type GinkgoFlagSection struct {
73	Key         string
74	Style       string
75	Succinct    bool
76	Heading     string
77	Description string
78}
79
80type GinkgoFlagSections []GinkgoFlagSection
81
82func (gfs GinkgoFlagSections) Lookup(key string) (GinkgoFlagSection, bool) {
83	for _, section := range gfs {
84		if section.Key == key {
85			return section, true
86		}
87	}
88
89	return GinkgoFlagSection{}, false
90}
91
92type GinkgoFlagSet struct {
93	flags    GinkgoFlags
94	bindings interface{}
95
96	sections            GinkgoFlagSections
97	extraGoFlagsSection GinkgoFlagSection
98
99	flagSet *flag.FlagSet
100}
101
102// Call NewGinkgoFlagSet to create GinkgoFlagSet that creates and binds to it's own *flag.FlagSet
103func NewGinkgoFlagSet(flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections) (GinkgoFlagSet, error) {
104	return bindFlagSet(GinkgoFlagSet{
105		flags:    flags,
106		bindings: bindings,
107		sections: sections,
108	}, nil)
109}
110
111// Call NewGinkgoFlagSet to create GinkgoFlagSet that extends an existing *flag.FlagSet
112func NewAttachedGinkgoFlagSet(flagSet *flag.FlagSet, flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections, extraGoFlagsSection GinkgoFlagSection) (GinkgoFlagSet, error) {
113	return bindFlagSet(GinkgoFlagSet{
114		flags:               flags,
115		bindings:            bindings,
116		sections:            sections,
117		extraGoFlagsSection: extraGoFlagsSection,
118	}, flagSet)
119}
120
121func bindFlagSet(f GinkgoFlagSet, flagSet *flag.FlagSet) (GinkgoFlagSet, error) {
122	if flagSet == nil {
123		f.flagSet = flag.NewFlagSet("", flag.ContinueOnError)
124		//suppress all output as Ginkgo is responsible for formatting usage
125		f.flagSet.SetOutput(io.Discard)
126	} else {
127		f.flagSet = flagSet
128		//we're piggybacking on an existing flagset (typically go test) so we have limited control
129		//on user feedback
130		f.flagSet.Usage = f.substituteUsage
131	}
132
133	for _, flag := range f.flags {
134		name := flag.Name
135
136		deprecatedUsage := "[DEPRECATED]"
137		deprecatedName := flag.DeprecatedName
138		if name != "" {
139			deprecatedUsage = fmt.Sprintf("[DEPRECATED] use --%s instead", name)
140		} else if flag.Usage != "" {
141			deprecatedUsage += " " + flag.Usage
142		}
143
144		value, ok := valueAtKeyPath(f.bindings, flag.KeyPath)
145		if !ok {
146			return GinkgoFlagSet{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath)
147		}
148
149		iface, addr := value.Interface(), value.Addr().Interface()
150
151		switch value.Type() {
152		case reflect.TypeOf(string("")):
153			if name != "" {
154				f.flagSet.StringVar(addr.(*string), name, iface.(string), flag.Usage)
155			}
156			if deprecatedName != "" {
157				f.flagSet.StringVar(addr.(*string), deprecatedName, iface.(string), deprecatedUsage)
158			}
159		case reflect.TypeOf(int64(0)):
160			if name != "" {
161				f.flagSet.Int64Var(addr.(*int64), name, iface.(int64), flag.Usage)
162			}
163			if deprecatedName != "" {
164				f.flagSet.Int64Var(addr.(*int64), deprecatedName, iface.(int64), deprecatedUsage)
165			}
166		case reflect.TypeOf(float64(0)):
167			if name != "" {
168				f.flagSet.Float64Var(addr.(*float64), name, iface.(float64), flag.Usage)
169			}
170			if deprecatedName != "" {
171				f.flagSet.Float64Var(addr.(*float64), deprecatedName, iface.(float64), deprecatedUsage)
172			}
173		case reflect.TypeOf(int(0)):
174			if name != "" {
175				f.flagSet.IntVar(addr.(*int), name, iface.(int), flag.Usage)
176			}
177			if deprecatedName != "" {
178				f.flagSet.IntVar(addr.(*int), deprecatedName, iface.(int), deprecatedUsage)
179			}
180		case reflect.TypeOf(bool(true)):
181			if name != "" {
182				f.flagSet.BoolVar(addr.(*bool), name, iface.(bool), flag.Usage)
183			}
184			if deprecatedName != "" {
185				f.flagSet.BoolVar(addr.(*bool), deprecatedName, iface.(bool), deprecatedUsage)
186			}
187		case reflect.TypeOf(time.Duration(0)):
188			if name != "" {
189				f.flagSet.DurationVar(addr.(*time.Duration), name, iface.(time.Duration), flag.Usage)
190			}
191			if deprecatedName != "" {
192				f.flagSet.DurationVar(addr.(*time.Duration), deprecatedName, iface.(time.Duration), deprecatedUsage)
193			}
194
195		case reflect.TypeOf([]string{}):
196			if name != "" {
197				f.flagSet.Var(stringSliceVar{value}, name, flag.Usage)
198			}
199			if deprecatedName != "" {
200				f.flagSet.Var(stringSliceVar{value}, deprecatedName, deprecatedUsage)
201			}
202		default:
203			return GinkgoFlagSet{}, fmt.Errorf("unsupported type %T", iface)
204		}
205	}
206
207	return f, nil
208}
209
210func (f GinkgoFlagSet) IsZero() bool {
211	return f.flagSet == nil
212}
213
214func (f GinkgoFlagSet) WasSet(name string) bool {
215	found := false
216	f.flagSet.Visit(func(f *flag.Flag) {
217		if f.Name == name {
218			found = true
219		}
220	})
221
222	return found
223}
224
225func (f GinkgoFlagSet) Lookup(name string) *flag.Flag {
226	return f.flagSet.Lookup(name)
227}
228
229func (f GinkgoFlagSet) Parse(args []string) ([]string, error) {
230	if f.IsZero() {
231		return args, nil
232	}
233	err := f.flagSet.Parse(args)
234	if err != nil {
235		return []string{}, err
236	}
237	return f.flagSet.Args(), nil
238}
239
240func (f GinkgoFlagSet) ValidateDeprecations(deprecationTracker *DeprecationTracker) {
241	if f.IsZero() {
242		return
243	}
244	f.flagSet.Visit(func(flag *flag.Flag) {
245		for _, ginkgoFlag := range f.flags {
246			if ginkgoFlag.DeprecatedName != "" && strings.HasSuffix(flag.Name, ginkgoFlag.DeprecatedName) {
247				message := fmt.Sprintf("--%s is deprecated", ginkgoFlag.DeprecatedName)
248				if ginkgoFlag.Name != "" {
249					message = fmt.Sprintf("--%s is deprecated, use --%s instead", ginkgoFlag.DeprecatedName, ginkgoFlag.Name)
250				} else if ginkgoFlag.Usage != "" {
251					message += " " + ginkgoFlag.Usage
252				}
253
254				deprecationTracker.TrackDeprecation(Deprecation{
255					Message: message,
256					DocLink: ginkgoFlag.DeprecatedDocLink,
257					Version: ginkgoFlag.DeprecatedVersion,
258				})
259			}
260		}
261	})
262}
263
264func (f GinkgoFlagSet) Usage() string {
265	if f.IsZero() {
266		return ""
267	}
268	groupedFlags := map[GinkgoFlagSection]GinkgoFlags{}
269	ungroupedFlags := GinkgoFlags{}
270	managedFlags := map[string]bool{}
271	extraGoFlags := []*flag.Flag{}
272
273	for _, flag := range f.flags {
274		managedFlags[flag.Name] = true
275		managedFlags[flag.DeprecatedName] = true
276
277		if flag.Name == "" {
278			continue
279		}
280
281		section, ok := f.sections.Lookup(flag.SectionKey)
282		if ok {
283			groupedFlags[section] = append(groupedFlags[section], flag)
284		} else {
285			ungroupedFlags = append(ungroupedFlags, flag)
286		}
287	}
288
289	f.flagSet.VisitAll(func(flag *flag.Flag) {
290		if !managedFlags[flag.Name] {
291			extraGoFlags = append(extraGoFlags, flag)
292		}
293	})
294
295	out := ""
296	for _, section := range f.sections {
297		flags := groupedFlags[section]
298		if len(flags) == 0 {
299			continue
300		}
301		out += f.usageForSection(section)
302		if section.Succinct {
303			succinctFlags := []string{}
304			for _, flag := range flags {
305				if flag.Name != "" {
306					succinctFlags = append(succinctFlags, fmt.Sprintf("--%s", flag.Name))
307				}
308			}
309			out += formatter.Fiw(1, formatter.COLS, section.Style+strings.Join(succinctFlags, ", ")+"{{/}}\n")
310		} else {
311			for _, flag := range flags {
312				out += f.usageForFlag(flag, section.Style)
313			}
314		}
315		out += "\n"
316	}
317	if len(ungroupedFlags) > 0 {
318		for _, flag := range ungroupedFlags {
319			out += f.usageForFlag(flag, "")
320		}
321		out += "\n"
322	}
323	if len(extraGoFlags) > 0 {
324		out += f.usageForSection(f.extraGoFlagsSection)
325		for _, goFlag := range extraGoFlags {
326			out += f.usageForGoFlag(goFlag)
327		}
328	}
329
330	return out
331}
332
333func (f GinkgoFlagSet) substituteUsage() {
334	fmt.Fprintln(f.flagSet.Output(), f.Usage())
335}
336
337func valueAtKeyPath(root interface{}, keyPath string) (reflect.Value, bool) {
338	if len(keyPath) == 0 {
339		return reflect.Value{}, false
340	}
341
342	val := reflect.ValueOf(root)
343	components := strings.Split(keyPath, ".")
344	for _, component := range components {
345		val = reflect.Indirect(val)
346		switch val.Kind() {
347		case reflect.Map:
348			val = val.MapIndex(reflect.ValueOf(component))
349			if val.Kind() == reflect.Interface {
350				val = reflect.ValueOf(val.Interface())
351			}
352		case reflect.Struct:
353			val = val.FieldByName(component)
354		default:
355			return reflect.Value{}, false
356		}
357		if (val == reflect.Value{}) {
358			return reflect.Value{}, false
359		}
360	}
361
362	return val, true
363}
364
365func (f GinkgoFlagSet) usageForSection(section GinkgoFlagSection) string {
366	out := formatter.F(section.Style + "{{bold}}{{underline}}" + section.Heading + "{{/}}\n")
367	if section.Description != "" {
368		out += formatter.Fiw(0, formatter.COLS, section.Description+"\n")
369	}
370	return out
371}
372
373func (f GinkgoFlagSet) usageForFlag(flag GinkgoFlag, style string) string {
374	argument := flag.UsageArgument
375	defValue := flag.UsageDefaultValue
376	if argument == "" {
377		value, _ := valueAtKeyPath(f.bindings, flag.KeyPath)
378		switch value.Type() {
379		case reflect.TypeOf(string("")):
380			argument = "string"
381		case reflect.TypeOf(int64(0)), reflect.TypeOf(int(0)):
382			argument = "int"
383		case reflect.TypeOf(time.Duration(0)):
384			argument = "duration"
385		case reflect.TypeOf(float64(0)):
386			argument = "float"
387		case reflect.TypeOf([]string{}):
388			argument = "string"
389		}
390	}
391	if argument != "" {
392		argument = "[" + argument + "] "
393	}
394	if defValue != "" {
395		defValue = fmt.Sprintf("(default: %s)", defValue)
396	}
397	hyphens := "--"
398	if len(flag.Name) == 1 {
399		hyphens = "-"
400	}
401
402	out := formatter.Fi(1, style+"%s%s{{/}} %s{{gray}}%s{{/}}\n", hyphens, flag.Name, argument, defValue)
403	out += formatter.Fiw(2, formatter.COLS, "{{light-gray}}%s{{/}}\n", flag.Usage)
404	return out
405}
406
407func (f GinkgoFlagSet) usageForGoFlag(goFlag *flag.Flag) string {
408	//Taken directly from the flag package
409	out := fmt.Sprintf("  -%s", goFlag.Name)
410	name, usage := flag.UnquoteUsage(goFlag)
411	if len(name) > 0 {
412		out += " " + name
413	}
414	if len(out) <= 4 {
415		out += "\t"
416	} else {
417		out += "\n    \t"
418	}
419	out += strings.ReplaceAll(usage, "\n", "\n    \t")
420	out += "\n"
421	return out
422}
423
424type stringSliceVar struct {
425	slice reflect.Value
426}
427
428func (ssv stringSliceVar) String() string { return "" }
429func (ssv stringSliceVar) Set(s string) error {
430	ssv.slice.Set(reflect.AppendSlice(ssv.slice, reflect.ValueOf([]string{s})))
431	return nil
432}
433
434//given a set of GinkgoFlags and bindings, generate flag arguments suitable to be passed to an application with that set of flags configured.
435func GenerateFlagArgs(flags GinkgoFlags, bindings interface{}) ([]string, error) {
436	result := []string{}
437	for _, flag := range flags {
438		name := flag.ExportAs
439		if name == "" {
440			name = flag.Name
441		}
442		if name == "" {
443			continue
444		}
445
446		value, ok := valueAtKeyPath(bindings, flag.KeyPath)
447		if !ok {
448			return []string{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath)
449		}
450
451		iface := value.Interface()
452		switch value.Type() {
453		case reflect.TypeOf(string("")):
454			if iface.(string) != "" {
455				result = append(result, fmt.Sprintf("--%s=%s", name, iface))
456			}
457		case reflect.TypeOf(int64(0)):
458			if iface.(int64) != 0 {
459				result = append(result, fmt.Sprintf("--%s=%d", name, iface))
460			}
461		case reflect.TypeOf(float64(0)):
462			if iface.(float64) != 0 {
463				result = append(result, fmt.Sprintf("--%s=%f", name, iface))
464			}
465		case reflect.TypeOf(int(0)):
466			if iface.(int) != 0 {
467				result = append(result, fmt.Sprintf("--%s=%d", name, iface))
468			}
469		case reflect.TypeOf(bool(true)):
470			if iface.(bool) {
471				result = append(result, fmt.Sprintf("--%s", name))
472			}
473		case reflect.TypeOf(time.Duration(0)):
474			if iface.(time.Duration) != time.Duration(0) {
475				result = append(result, fmt.Sprintf("--%s=%s", name, iface))
476			}
477
478		case reflect.TypeOf([]string{}):
479			strings := iface.([]string)
480			for _, s := range strings {
481				result = append(result, fmt.Sprintf("--%s=%s", name, s))
482			}
483		default:
484			return []string{}, fmt.Errorf("unsupported type %T", iface)
485		}
486	}
487
488	return result, nil
489}
490
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Most used method in

Trigger substituteUsage code on LambdaTest Cloud Grid

Execute automation tests with substituteUsage on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)