From e1d48ef104443d7382b203f8afe9637f1d972630 Mon Sep 17 00:00:00 2001 From: gedi Date: Thu, 11 Jun 2015 10:02:58 +0300 Subject: [PATCH] package documentation --- README.md | 4 +- gherkin/ast.go | 3 + gherkin/example/ls.feature | 15 ++++ gherkin/example/main.go | 21 +++++ ...{parse_feature_test.go => feature_test.go} | 0 gherkin/{parse.go => gherkin.go} | 77 +++++++++++++++++++ .../{parse_steps_test.go => steps_test.go} | 0 godog.go | 35 +++++++++ runner.go | 1 - steps.go | 21 +++++ 10 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 gherkin/example/ls.feature create mode 100644 gherkin/example/main.go rename gherkin/{parse_feature_test.go => feature_test.go} (100%) rename gherkin/{parse.go => gherkin.go} (71%) rename gherkin/{parse_steps_test.go => steps_test.go} (100%) create mode 100644 godog.go delete mode 100644 runner.go diff --git a/README.md b/README.md index d0fdfff..df7eca5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ +[![Build Status](https://travis-ci.org/DATA-DOG/godog.png)](https://travis-ci.org/DATA-DOG/godog) + # Godog -**Godog** is an open source behavior-driven development framework for [golang][golang] programming language. +**Godog** is an open source behavior-driven development framework for [go][golang] programming language. What is behavior-driven development, you ask? It’s the idea that you start by writing human-readable sentences that describe a feature of your application and how it should work, and only then implement this behavior in software. diff --git a/gherkin/ast.go b/gherkin/ast.go index 2866031..7f29b15 100644 --- a/gherkin/ast.go +++ b/gherkin/ast.go @@ -7,6 +7,9 @@ type item struct { value *lexer.Token } +// AST is a linked list to store gherkin Tokens +// used to insert errors and other details into +// the token tree type AST struct { head, tail *item } diff --git a/gherkin/example/ls.feature b/gherkin/example/ls.feature new file mode 100644 index 0000000..931d436 --- /dev/null +++ b/gherkin/example/ls.feature @@ -0,0 +1,15 @@ +Feature: ls + In order to see the directory structure + As a UNIX user + I need to be able to list the current directory's contents + + Scenario: + Given I am in a directory "test" + And I have a file named "foo" + And I have a file named "bar" + When I run "ls" + Then I should get: + """ + bar + foo + """ diff --git a/gherkin/example/main.go b/gherkin/example/main.go new file mode 100644 index 0000000..bf14400 --- /dev/null +++ b/gherkin/example/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "log" + "os" + + "github.com/DATA-DOG/godog/gherkin" +) + +func main() { + feature, err := gherkin.Parse("ls.feature") + switch { + case err == gherkin.ErrEmpty: + log.Println("the feature file is empty and does not describe any feature") + return + case err != nil: + log.Println("the feature file is incorrect or could not be read:", err) + os.Exit(1) + } + log.Println("have parsed a feature:", feature.Title, "with", len(feature.Scenarios), "scenarios") +} diff --git a/gherkin/parse_feature_test.go b/gherkin/feature_test.go similarity index 100% rename from gherkin/parse_feature_test.go rename to gherkin/feature_test.go diff --git a/gherkin/parse.go b/gherkin/gherkin.go similarity index 71% rename from gherkin/parse.go rename to gherkin/gherkin.go index 06e2fec..f78ec51 100644 --- a/gherkin/parse.go +++ b/gherkin/gherkin.go @@ -1,3 +1,61 @@ +/* +Package gherkin is a gherkin language parser based on https://cucumber.io/docs/reference +specification. It parses a feature file into the it's structural representation. It also +creates an AST tree of gherkin Tokens read from the file. + +With gherkin language you can describe your application behavior as features in +human-readable and machine friendly language. + +For example, imagine you’re about to create the famous UNIX ls command. +Before you begin, you describe how the feature should work, see the example below.. + +Example: + Feature: ls + In order to see the directory structure + As a UNIX user + I need to be able to list the current directory's contents + + Scenario: + Given I am in a directory "test" + And I have a file named "foo" + And I have a file named "bar" + When I run "ls" + Then I should get: + """ + bar + foo + """ + +As a developer, your work is done as soon as you’ve made the ls command behave as +described in the Scenario. + +To read the feature in the example above.. + +Example: + package main + + import ( + "log" + "os" + + "github.com/DATA-DOG/godog/gherkin" + ) + + func main() { + feature, err := gherkin.Parse("ls.feature") + switch { + case err == gherkin.ErrEmpty: + log.Println("the feature file is empty and does not describe any feature") + return + case err != nil: + log.Println("the feature file is incorrect or could not be read:", err) + os.Exit(1) + } + log.Println("have parsed a feature:", feature.Title, "with", len(feature.Scenarios), "scenarios") + } + +Now the feature is available in the structure. +*/ package gherkin import ( @@ -10,8 +68,15 @@ import ( "github.com/DATA-DOG/godog/gherkin/lexer" ) +// Tag is gherkin feature or scenario tag. +// it may be used to filter scenarios. +// +// tags may be set for a feature, in that case it will +// be merged with all scenario tags. or specifically +// to a single scenario type Tag string +// Tags is an array of tags type Tags []Tag func (t Tags) Has(tag Tag) bool { @@ -23,6 +88,7 @@ func (t Tags) Has(tag Tag) bool { return false } +// Scenario describes the scenario details type Scenario struct { Title string Steps []*Step @@ -30,11 +96,13 @@ type Scenario struct { Comment string } +// Background steps are run before every scenario type Background struct { Steps []*Step Comment string } +// StepType is a general type of step type StepType string const ( @@ -43,6 +111,7 @@ const ( Then StepType = "Then" ) +// Step describes a Scenario or Background step type Step struct { Text string Comment string @@ -51,6 +120,7 @@ type Step struct { Table *Table } +// Feature describes the whole feature type Feature struct { Path string Tags Tags @@ -62,10 +132,12 @@ type Feature struct { Comment string } +// PyString is a multiline text object used with step definition type PyString struct { Body string } +// Table is a row group object used with step definition type Table struct { rows [][]string } @@ -78,6 +150,8 @@ var allSteps = []lexer.TokenType{ lexer.BUT, } +// ErrEmpty is returned in case if feature file +// is completely empty. May be ignored in some use cases var ErrEmpty = errors.New("the feature file is empty") type parser struct { @@ -87,6 +161,9 @@ type parser struct { peeked *lexer.Token } +// Parse the feature file on the given path into +// the Feature struct +// Returns a Feature struct and error if there is any func Parse(path string) (*Feature, error) { file, err := os.Open(path) if err != nil { diff --git a/gherkin/parse_steps_test.go b/gherkin/steps_test.go similarity index 100% rename from gherkin/parse_steps_test.go rename to gherkin/steps_test.go diff --git a/godog.go b/godog.go new file mode 100644 index 0000000..6b6303b --- /dev/null +++ b/godog.go @@ -0,0 +1,35 @@ +/* +Package godog is a behavior-driven development framework, a tool to describe your +application based on the behavior and run these specifications. The features are +described by a human-readable gherkin language. + +For example, imagine you’re about to create the famous UNIX ls command. +Before you begin, you describe how the feature should work, see the example below.. + +Example: + Feature: ls + In order to see the directory structure + As a UNIX user + I need to be able to list the current directory's contents + + Scenario: + Given I am in a directory "test" + And I have a file named "foo" + And I have a file named "bar" + When I run "ls" + Then I should get: + """ + bar + foo + """ + +As a developer, your work is done as soon as you’ve made the ls command behave as +described in the Scenario. + +Now, wouldn’t it be cool if something could read this sentence and use it to actually +run a test against the ls command? Hey, that’s exactly what this package does! +As you’ll see, Godog is easy to learn, quick to use, and will put the fun back into tests. + +Godog was inspired by Behat and the above description is taken from it's documentation. +*/ +package godog diff --git a/runner.go b/runner.go deleted file mode 100644 index 5d7c8c5..0000000 --- a/runner.go +++ /dev/null @@ -1 +0,0 @@ -package godog diff --git a/steps.go b/steps.go index b973f28..2b8c988 100644 --- a/steps.go +++ b/steps.go @@ -4,16 +4,37 @@ import "regexp" var stepHandlers map[*regexp.Regexp]StepHandler +// Objects implementing the StepHandler interface can be +// registered as step definitions in godog +// +// HandleStep method receives all arguments which +// will be matched according to the regular expression +// which is passed with a step registration. +// The error in return - represents a reason of failure. +// +// Returning signals that the step has finished +// and that the feature runner can move on to the next +// step. type StepHandler interface { HandleStep(args ...interface{}) error } +// StepHandlerFunc type is an adapter to allow the use of +// ordinary functions as Step handlers. If f is a function +// with the appropriate signature, StepHandlerFunc(f) is a +// StepHandler object that calls f. type StepHandlerFunc func(...interface{}) error +// HandleStep calls f(step_arguments...). func (f StepHandlerFunc) HandleStep(args ...interface{}) error { return f(args...) } +// Step registers a StepHandler which will be triggered +// if regular expression will match a step from a feature file. +// +// If none of the StepHandlers are matched, then a pending +// step error will be raised. func Step(exp *regexp.Regexp, h StepHandler) { stepHandlers[exp] = h }