Skip to content

Commit

Permalink
feat!: prepare the third version (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
hedhyw committed Jun 4, 2023
1 parent 79c5840 commit 83c8fbf
Show file tree
Hide file tree
Showing 94 changed files with 745 additions and 555 deletions.
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

0 comments on commit 83c8fbf

Please sign in to comment.