Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: prepare the third version #90

Merged
merged 2 commits into from
Jun 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .golangci.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"varcheck",
"ifshort",
"nosnakecase",
"rowserrcheck"
"rowserrcheck",
"depguard"
]
},
"linters-settings": {
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GOLANG_CI_LINT_VER:=v1.51.2
GOLANG_CI_LINT_VER:=v1.53.2
OUT_BIN?=${PWD}/bin/gherkingen
COVER_PACKAGES=./...
VERSION?=${shell git describe --tags}
Expand Down
109 changes: 36 additions & 73 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ The generator is very customizable, it is possible to customize an output for an

# What is for?
## Simple example

**Given** [feature](internal/generator/examples/readme.feature) [[reference](https://cucumber.io/docs/gherkin/reference/)]:
```feature
Feature: Application command line tool
Scenario: User wants to see usage information
When flag <flag> is provided
When the application is started with <flag>
Then usage should be printed <printed>
And exit status should be <exit_status>
Examples:
Expand All @@ -34,9 +35,11 @@ Feature: Application command line tool

```go
func TestApplicationCommandLineTool(t *testing.T) {
f := bdd.NewFeature(t, "Application command line tool")
t.Parallel()

t.Run("User wants to see usage information", func(t *testing.T) {
t.Parallel()

f.Scenario("User wants to see usage information", func(t *testing.T, f *bdd.Feature) {
type testCase struct {
Flag string `field:"<flag>"`
ExitStatus int `field:"<exit_status>"`
Expand All @@ -49,94 +52,52 @@ func TestApplicationCommandLineTool(t *testing.T) {
"-invalid_1_false": {"-invalid", 1, false},
}

f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
f.When("flag <flag> is provided", func() {
for name, testCase := range testCases {
testCase := testCase

})
f.Then("usage should be printed <printed>", func() {
t.Run(name, func(t *testing.T) {
t.Parallel()

})
f.And("exit status should be <exit_status>", func() {
// When the application is started with <flag>.

// Then usage should be printed <printed>.

// And exit status should be <exit_status>.

})
})
}
})
}
```

**Then** on failure next logs will be printed:

```feature
Feature: Application command line tool
Scenario: User wants to see usage information
# TestCase: {Flag:-invalid ExitStatus:1 Printed:false}
When flag -invalid is provided
Then usage should be printed false
And exit status should be 1
```

**Example** implementation:
```go
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
var exitStatus int
arguments := []string{}

f.When("flag <flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
f.Then("usage should be printed <printed>", func() {
var output string
output, exitStatus = runApp(t, arguments)
assert.Equal(t, tc.Printed, strings.Contains(output, "usage"))
})
f.And("exit status should be <exit_status>", func() {
assert.Equal(t, tc.ExitStatus, exitStatus)
})
})
```

## Simplified template

A simplified template is also available. It uses only the std [testing](https://pkg.go.dev/testing) package without any other dependency. Steps are defined by comments.
Provide `-template @/std.simple.v1.go.tmpl` to to use [this](internal/assets/std.simple.v1.go.tmpl) template.

```go
func TestApplicationCommandLineTool(t *testing.T) {
t.Run(name, func(t *testing.T) {
t.Parallel()

t.Run("User wants to see usage information", func(t *testing.T) {
t.Parallel()

type testCase struct {
Flag string `field:"<flag>"`
ExitStatus int `field:"<exit_status>"`
Printed bool `field:"<printed>"`
}
// When flag <flag> is provided.
arguments := []string{testCase.Flag}

testCases := map[string]testCase{
"--help_0_true": {"--help", 0, true},
"-help_0_true": {"-help", 0, true},
"-invalid_1_false": {"-invalid", 1, false},
}
// Then usage should be printed <printed>.
var output string
output, exitStatus = runApp(t, arguments)
assert.Equal(t, testCase.Printed, strings.Contains(output, "usage"))

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
// When flag <flag> is provided.

// Then usage should be printed <printed>.

// And exit status should be <exit_status>.

})
}
})
}
// And exit status should be <exit_status>.
assert.Equal(t, testCase.ExitStatus, exitStatus)
})
```

## More advanced example

See [internal/app/app.feature](internal/app/app.feature) and [internal/app/app_test.go](internal/app/app_test.go).

## Version 3 changes

1. Simplified template is set by default. In order to use the default template from the previous versions, provide the following flag `-template @/std.struct.v1.go.tmpl`.
2. All tests will have `t.Parallel` by default. This behaviour can be disabled by providing the flag `-disable-go-parallel`.

# Install

## Package
Expand Down Expand Up @@ -177,7 +138,7 @@ gherkingen -help
## Go

```bash
go install github.com/hedhyw/gherkingen/v2/cmd/gherkingen@latest
go install github.com/hedhyw/gherkingen/v3/cmd/gherkingen@latest
# Notice: gherkingen -version will return "unknown" version.
```

Expand Down Expand Up @@ -219,10 +180,12 @@ gherkingen -list
gherkingen --help

Usage of gherkingen [FEATURE_FILE]:
-disable-go-parallel
disable execution of tests in parallel
-format string
output format: autodetect, json, go, raw (default "autodetect")
-go-parallel
add parallel mark
add parallel mark (deprecated, enabled by default) (default true)
-help
print usage
-list
Expand All @@ -232,7 +195,7 @@ Usage of gherkingen [FEATURE_FILE]:
-permanent-ids
The same calls to the generator always produces the same output
-template string
template file (default "@/std.struct.v1.go.tmpl")
template file (default "@/std.simple.v1.go.tmpl")
-version
print version
```
Expand Down
2 changes: 1 addition & 1 deletion cmd/gherkingen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"os"

"github.com/hedhyw/gherkingen/v2/internal/app"
"github.com/hedhyw/gherkingen/v3/internal/app"
)

// Version will be set on build.
Expand Down
11 changes: 0 additions & 11 deletions cmd/gherkingen/main_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/hedhyw/gherkingen/v2
module github.com/hedhyw/gherkingen/v3

go 1.20

Expand Down
11 changes: 5 additions & 6 deletions internal/app/app.feature
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ Feature: Application command line tool
| true |
| false |

Scenario: User gives an invalid flag
Scenario: User provides an invalid flag
When flag -invalid is provided
Then a generation failed
Then an error is returned

Scenario: User wants to know version
Scenario: User asks for a version
When <flag> is provided
Then version is printed
Examples:
Expand All @@ -73,11 +73,10 @@ Feature: Application command line tool
| app.feature | not_found |

Scenario: User wants to run tests in parallel
When `-go-parallel` is provided
And `scenario.feature` is given
When `scenario.feature` is given
Then generated code contains `t.Parallel()`

Scenario: User wants to run tests sequentially
When `-go-parallel` is not provided
When `-disable-go-parallel` is provided
And `scenario.feature` is given
Then generated code doesn't contain `t.Parallel()`
69 changes: 44 additions & 25 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,83 @@ import (
"strings"
"time"

"github.com/hedhyw/gherkingen/v2/internal/model"
"github.com/hedhyw/gherkingen/v3/internal/model"

"github.com/google/uuid"
)

const (
internalPathPrefix = "@/"
defaultTemplate = "std.struct.v1.go.tmpl"
internalPathPrefix = "@/"
defaultTemplate = "std.simple.v1.go.tmpl"
defaultDisableGoParallel = false
defaultOutputFormat = model.FormatAutoDetect
)

// Run the application.
func Run(arguments []string, out io.Writer, version string) (err error) {
flag.CommandLine.Init(flag.CommandLine.Name(), flag.ContinueOnError)
flag.CommandLine.SetOutput(out)
flagSet := flag.NewFlagSet(flag.CommandLine.Name(), flag.ContinueOnError)
flagSet.SetOutput(out)

outputFormat := flag.String(
outputFormat := flagSet.String(
"format",
string(model.FormatAutoDetect),
string(defaultOutputFormat),
"output format: "+strings.Join(model.Formats(), ", "),
)
templateFile := flag.String(
templateFile := flagSet.String(
"template",
internalPathPrefix+defaultTemplate,
"template file",
)
permanentIDs := flag.Bool(
permanentIDs := flagSet.Bool(
"permanent-ids",
false,
"The same calls to the generator always produces the same output",
)
helpCmd := flag.Bool(
helpCmd := flagSet.Bool(
"help",
false,
"print usage",
)
goParallel := flag.Bool(
_ = flagSet.Bool(
"go-parallel",
false,
"add parallel mark",
!defaultDisableGoParallel,
"add parallel mark (deprecated, enabled by default)",
)
disableGoParallel := flagSet.Bool(
"disable-go-parallel",
defaultDisableGoParallel,
"disable execution of tests in parallel",
)
listCmd := flag.Bool(
listCmd := flagSet.Bool(
"list",
false,
"list internal templates",
)
packageName := flag.String(
packageName := flagSet.String(
"package",
"generated_test",
"name of the generated package",
)
versionCmd := flag.Bool(
versionCmd := flagSet.Bool(
"version",
false,
"print version",
)
if err = flag.CommandLine.Parse(arguments); err != nil {
if err = flagSet.Parse(arguments); err != nil {
return err
}

var seed int64

if *permanentIDs {
// nolint:gosec // Usage for uniq ids.
uuid.SetRand(rand.New(rand.NewSource(0)))
seed = 1
} else {
// nolint:gosec // Usage for uniq ids.
uuid.SetRand(rand.New(rand.NewSource(time.Now().UnixNano())))
seed = time.Now().UnixNano()
}

var inputFile string
if flag.NArg() == 1 {
inputFile = flag.Args()[0]
if flagSet.NArg() == 1 {
inputFile = flagSet.Args()[0]
}

switch {
Expand All @@ -85,15 +92,27 @@ func Run(arguments []string, out io.Writer, version string) (err error) {
case *listCmd:
return runListTemplates(out)
case *helpCmd, inputFile == "":
return runHelp()
return runHelp(flagSet)
default:
return runGenerator(appArgs{
Output: out,
OutputFormat: model.Format(*outputFormat),
TemplateFile: *templateFile,
InputFile: inputFile,
PackageName: *packageName,
GoParallel: *goParallel,
GoParallel: !(*disableGoParallel),
GenerateUUID: newUUIDRandomGenerator(seed),
})
}
}

func newUUIDRandomGenerator(seed int64) func() string {
// nolint:gosec // Usage for uniq ids.
randomGenerator := rand.New(rand.NewSource(seed))

return func() string {
uuidValue, err := uuid.NewRandomFromReader(randomGenerator)

return uuid.Must(uuidValue, err).String()
}
}
Loading