File: bootstrap_command.go

package info (click to toggle)
golang-github-onsi-ginkgo-v2 2.22.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,060 kB
  • sloc: javascript: 59; makefile: 23; sh: 14
file content (133 lines) | stat: -rw-r--r-- 4,463 bytes parent folder | download
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
package generators

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"text/template"

	sprig "github.com/go-task/slim-sprig/v3"
	"github.com/onsi/ginkgo/v2/ginkgo/command"
	"github.com/onsi/ginkgo/v2/ginkgo/internal"
	"github.com/onsi/ginkgo/v2/types"
)

func BuildBootstrapCommand() command.Command {
	conf := GeneratorsConfig{}
	flags, err := types.NewGinkgoFlagSet(
		types.GinkgoFlags{
			{Name: "agouti", KeyPath: "Agouti",
				Usage: "If set, bootstrap will generate a bootstrap file for writing Agouti tests"},
			{Name: "nodot", KeyPath: "NoDot",
				Usage: "If set, bootstrap will generate a bootstrap test file that does not dot-import ginkgo and gomega"},
			{Name: "internal", KeyPath: "Internal",
				Usage: "If set, bootstrap will generate a bootstrap test file that uses the regular package name (i.e. `package X`, not `package X_test`)"},
			{Name: "template", KeyPath: "CustomTemplate",
				UsageArgument: "template-file",
				Usage:         "If specified, generate will use the contents of the file passed as the bootstrap template"},
			{Name: "template-data", KeyPath: "CustomTemplateData",
				UsageArgument: "template-data-file",
				Usage:         "If specified, generate will use the contents of the file passed as data to be rendered in the bootstrap template"},
		},
		&conf,
		types.GinkgoFlagSections{},
	)

	if err != nil {
		panic(err)
	}

	return command.Command{
		Name:     "bootstrap",
		Usage:    "ginkgo bootstrap",
		ShortDoc: "Bootstrap a test suite for the current package",
		Documentation: `Tests written in Ginkgo and Gomega require a small amount of boilerplate to hook into Go's testing infrastructure.

{{bold}}ginkgo bootstrap{{/}} generates this boilerplate for you in a file named X_suite_test.go where X is the name of the package under test.`,
		DocLink: "generators",
		Flags:   flags,
		Command: func(_ []string, _ []string) {
			generateBootstrap(conf)
		},
	}
}

type bootstrapData struct {
	Package       string
	FormattedName string

	GinkgoImport  string
	GomegaImport  string
	GinkgoPackage string
	GomegaPackage string
	CustomData    map[string]any
}

func generateBootstrap(conf GeneratorsConfig) {
	packageName, bootstrapFilePrefix, formattedName := getPackageAndFormattedName()

	data := bootstrapData{
		Package:       determinePackageName(packageName, conf.Internal),
		FormattedName: formattedName,

		GinkgoImport:  `. "github.com/onsi/ginkgo/v2"`,
		GomegaImport:  `. "github.com/onsi/gomega"`,
		GinkgoPackage: "",
		GomegaPackage: "",
	}

	if conf.NoDot {
		data.GinkgoImport = `"github.com/onsi/ginkgo/v2"`
		data.GomegaImport = `"github.com/onsi/gomega"`
		data.GinkgoPackage = `ginkgo.`
		data.GomegaPackage = `gomega.`
	}

	targetFile := fmt.Sprintf("%s_suite_test.go", bootstrapFilePrefix)
	if internal.FileExists(targetFile) {
		command.AbortWith("{{bold}}%s{{/}} already exists", targetFile)
	} else {
		fmt.Printf("Generating ginkgo test suite bootstrap for %s in:\n\t%s\n", packageName, targetFile)
	}

	f, err := os.Create(targetFile)
	command.AbortIfError("Failed to create file:", err)
	defer f.Close()

	var templateText string
	if conf.CustomTemplate != "" {
		tpl, err := os.ReadFile(conf.CustomTemplate)
		command.AbortIfError("Failed to read custom bootstrap file:", err)
		templateText = string(tpl)
		if conf.CustomTemplateData != "" {
			var tplCustomDataMap map[string]any
			tplCustomData, err := os.ReadFile(conf.CustomTemplateData)
			command.AbortIfError("Failed to read custom boostrap data file:", err)
			if !json.Valid([]byte(tplCustomData)) {
				command.AbortWith("Invalid JSON object in custom data file.")
			}
			//create map from the custom template data
			json.Unmarshal(tplCustomData, &tplCustomDataMap)
			data.CustomData = tplCustomDataMap
		}
	} else if conf.Agouti {
		templateText = agoutiBootstrapText
	} else {
		templateText = bootstrapText
	}

	//Setting the option to explicitly fail if template is rendered trying to access missing key
	bootstrapTemplate, err := template.New("bootstrap").Funcs(sprig.TxtFuncMap()).Option("missingkey=error").Parse(templateText)
	command.AbortIfError("Failed to parse bootstrap template:", err)

	buf := &bytes.Buffer{}
	//Being explicit about failing sooner during template rendering
	//when accessing custom data rather than during the go fmt command
	err = bootstrapTemplate.Execute(buf, data)
	command.AbortIfError("Failed to render bootstrap template:", err)

	buf.WriteTo(f)

	internal.GoFmt(targetFile)
}