github.com/Secbyte/godog@v0.7.14-0.20200116175429-d8f0aeeb70cf/run_test.go (about)

     1  package godog
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/DATA-DOG/godog/colors"
    13  	"github.com/DATA-DOG/godog/gherkin"
    14  )
    15  
    16  func okStep() error {
    17  	return nil
    18  }
    19  
    20  func TestPrintsStepDefinitions(t *testing.T) {
    21  	var buf bytes.Buffer
    22  	w := colors.Uncolored(&buf)
    23  	s := &Suite{}
    24  
    25  	steps := []string{
    26  		"^passing step$",
    27  		`^with name "([^"])"`,
    28  	}
    29  
    30  	for _, step := range steps {
    31  		s.Step(step, okStep)
    32  	}
    33  	s.printStepDefinitions(w)
    34  
    35  	out := buf.String()
    36  	ref := `okStep`
    37  	for i, def := range strings.Split(strings.TrimSpace(out), "\n") {
    38  		if idx := strings.Index(def, steps[i]); idx == -1 {
    39  			t.Fatalf(`step "%s" was not found in output`, steps[i])
    40  		}
    41  		if idx := strings.Index(def, ref); idx == -1 {
    42  			t.Fatalf(`step definition reference "%s" was not found in output: "%s"`, ref, def)
    43  		}
    44  	}
    45  }
    46  
    47  func TestPrintsNoStepDefinitionsIfNoneFound(t *testing.T) {
    48  	var buf bytes.Buffer
    49  	w := colors.Uncolored(&buf)
    50  	s := &Suite{}
    51  	s.printStepDefinitions(w)
    52  
    53  	out := strings.TrimSpace(buf.String())
    54  	if out != "there were no contexts registered, could not find any step definition.." {
    55  		t.Fatalf("expected output does not match to: %s", out)
    56  	}
    57  }
    58  
    59  func TestFailsOrPassesBasedOnStrictModeWhenHasPendingSteps(t *testing.T) {
    60  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
    61  	if err != nil {
    62  		t.Fatalf("unexpected error: %v", err)
    63  	}
    64  
    65  	r := runner{
    66  		fmt:      progressFunc("progress", ioutil.Discard),
    67  		features: []*feature{&feature{Feature: feat}},
    68  		initializer: func(s *Suite) {
    69  			s.Step(`^one$`, func() error { return nil })
    70  			s.Step(`^two$`, func() error { return ErrPending })
    71  		},
    72  	}
    73  
    74  	if r.run() {
    75  		t.Fatal("the suite should have passed")
    76  	}
    77  
    78  	r.strict = true
    79  	if !r.run() {
    80  		t.Fatal("the suite should have failed")
    81  	}
    82  }
    83  
    84  func TestFailsOrPassesBasedOnStrictModeWhenHasUndefinedSteps(t *testing.T) {
    85  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
    86  	if err != nil {
    87  		t.Fatalf("unexpected error: %v", err)
    88  	}
    89  
    90  	r := runner{
    91  		fmt:      progressFunc("progress", ioutil.Discard),
    92  		features: []*feature{&feature{Feature: feat}},
    93  		initializer: func(s *Suite) {
    94  			s.Step(`^one$`, func() error { return nil })
    95  			// two - is undefined
    96  		},
    97  	}
    98  
    99  	if r.run() {
   100  		t.Fatal("the suite should have passed")
   101  	}
   102  
   103  	r.strict = true
   104  	if !r.run() {
   105  		t.Fatal("the suite should have failed")
   106  	}
   107  }
   108  
   109  func TestShouldFailOnError(t *testing.T) {
   110  	feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
   111  	if err != nil {
   112  		t.Fatalf("unexpected error: %v", err)
   113  	}
   114  
   115  	r := runner{
   116  		fmt:      progressFunc("progress", ioutil.Discard),
   117  		features: []*feature{&feature{Feature: feat}},
   118  		initializer: func(s *Suite) {
   119  			s.Step(`^one$`, func() error { return nil })
   120  			s.Step(`^two$`, func() error { return fmt.Errorf("error") })
   121  		},
   122  	}
   123  
   124  	if !r.run() {
   125  		t.Fatal("the suite should have failed")
   126  	}
   127  }
   128  
   129  func TestFailsWithConcurrencyOptionError(t *testing.T) {
   130  	stderr, closer := bufErrorPipe(t)
   131  	defer closer()
   132  	defer stderr.Close()
   133  
   134  	opt := Options{
   135  		Format:      "pretty",
   136  		Paths:       []string{"features/load:6"},
   137  		Concurrency: 2,
   138  		Output:      ioutil.Discard,
   139  	}
   140  
   141  	status := RunWithOptions("fails", func(_ *Suite) {}, opt)
   142  	if status != exitOptionError {
   143  		t.Fatalf("expected exit status to be 2, but was: %d", status)
   144  	}
   145  	closer()
   146  
   147  	b, err := ioutil.ReadAll(stderr)
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  
   152  	out := strings.TrimSpace(string(b))
   153  	if out != `format "pretty" does not support concurrent execution` {
   154  		t.Fatalf("unexpected error output: \"%s\"", out)
   155  	}
   156  }
   157  
   158  func TestFailsWithUnknownFormatterOptionError(t *testing.T) {
   159  	stderr, closer := bufErrorPipe(t)
   160  	defer closer()
   161  	defer stderr.Close()
   162  
   163  	opt := Options{
   164  		Format: "unknown",
   165  		Paths:  []string{"features/load:6"},
   166  		Output: ioutil.Discard,
   167  	}
   168  
   169  	status := RunWithOptions("fails", func(_ *Suite) {}, opt)
   170  	if status != exitOptionError {
   171  		t.Fatalf("expected exit status to be 2, but was: %d", status)
   172  	}
   173  	closer()
   174  
   175  	b, err := ioutil.ReadAll(stderr)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  
   180  	out := strings.TrimSpace(string(b))
   181  	if !strings.Contains(out, `unregistered formatter name: "unknown", use one of`) {
   182  		t.Fatalf("unexpected error output: %q", out)
   183  	}
   184  }
   185  
   186  func TestFailsWithOptionErrorWhenLookingForFeaturesInUnavailablePath(t *testing.T) {
   187  	stderr, closer := bufErrorPipe(t)
   188  	defer closer()
   189  	defer stderr.Close()
   190  
   191  	opt := Options{
   192  		Format: "progress",
   193  		Paths:  []string{"unavailable"},
   194  		Output: ioutil.Discard,
   195  	}
   196  
   197  	status := RunWithOptions("fails", func(_ *Suite) {}, opt)
   198  	if status != exitOptionError {
   199  		t.Fatalf("expected exit status to be 2, but was: %d", status)
   200  	}
   201  	closer()
   202  
   203  	b, err := ioutil.ReadAll(stderr)
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  	out := strings.TrimSpace(string(b))
   209  	if out != `feature path "unavailable" is not available` {
   210  		t.Fatalf("unexpected error output: \"%s\"", out)
   211  	}
   212  }
   213  
   214  func TestByDefaultRunsFeaturesPath(t *testing.T) {
   215  	opt := Options{
   216  		Format: "progress",
   217  		Output: ioutil.Discard,
   218  		Strict: true,
   219  	}
   220  
   221  	status := RunWithOptions("fails", func(_ *Suite) {}, opt)
   222  	// should fail in strict mode due to undefined steps
   223  	if status != exitFailure {
   224  		t.Fatalf("expected exit status to be 1, but was: %d", status)
   225  	}
   226  
   227  	opt.Strict = false
   228  	status = RunWithOptions("succeeds", func(_ *Suite) {}, opt)
   229  	// should succeed in non strict mode due to undefined steps
   230  	if status != exitSuccess {
   231  		t.Fatalf("expected exit status to be 0, but was: %d", status)
   232  	}
   233  }
   234  
   235  func bufErrorPipe(t *testing.T) (io.ReadCloser, func()) {
   236  	stderr := os.Stderr
   237  	r, w, err := os.Pipe()
   238  	if err != nil {
   239  		t.Fatal(err)
   240  	}
   241  
   242  	os.Stderr = w
   243  	return r, func() {
   244  		w.Close()
   245  		os.Stderr = stderr
   246  	}
   247  }
   248  
   249  func TestFeatureFilePathParser(t *testing.T) {
   250  
   251  	type Case struct {
   252  		input string
   253  		path  string
   254  		line  int
   255  	}
   256  
   257  	cases := []Case{
   258  		{"/home/test.feature", "/home/test.feature", -1},
   259  		{"/home/test.feature:21", "/home/test.feature", 21},
   260  		{"test.feature", "test.feature", -1},
   261  		{"test.feature:2", "test.feature", 2},
   262  		{"", "", -1},
   263  		{"/c:/home/test.feature", "/c:/home/test.feature", -1},
   264  		{"/c:/home/test.feature:3", "/c:/home/test.feature", 3},
   265  		{"D:\\home\\test.feature:3", "D:\\home\\test.feature", 3},
   266  	}
   267  
   268  	for i, c := range cases {
   269  		p, ln := extractFeaturePathLine(c.input)
   270  		if p != c.path {
   271  			t.Fatalf(`result path "%s" != "%s" at %d`, p, c.path, i)
   272  		}
   273  		if ln != c.line {
   274  			t.Fatalf(`result line "%d" != "%d" at %d`, ln, c.line, i)
   275  		}
   276  	}
   277  }
   278  
   279  func TestSucceedWithConcurrencyOption(t *testing.T) {
   280  	output := new(bytes.Buffer)
   281  
   282  	opt := Options{
   283  		Format:      "progress",
   284  		NoColors:    true,
   285  		Paths:       []string{"features"},
   286  		Concurrency: 2,
   287  		Output:      output,
   288  	}
   289  
   290  	expectedOutput := `...................................................................... 70
   291  ...................................................................... 140
   292  ...................................................................... 210
   293  .......................................                                249
   294  
   295  
   296  60 scenarios (60 passed)
   297  249 steps (249 passed)
   298  0s`
   299  
   300  	status := RunWithOptions("succeed", func(s *Suite) { SuiteContext(s) }, opt)
   301  	if status != exitSuccess {
   302  		t.Fatalf("expected exit status to be 0, but was: %d", status)
   303  	}
   304  
   305  	b, err := ioutil.ReadAll(output)
   306  	if err != nil {
   307  		t.Fatal(err)
   308  	}
   309  
   310  	out := strings.TrimSpace(string(b))
   311  	if out != expectedOutput {
   312  		t.Fatalf("unexpected output: \"%s\"", out)
   313  	}
   314  }