gitee.com/mirrors/gauge@v1.0.6/validation/validation_test.go (about)

     1  // Copyright 2015 ThoughtWorks, Inc.
     2  
     3  // This file is part of Gauge.
     4  
     5  // Gauge is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  
    10  // Gauge is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  
    15  // You should have received a copy of the GNU General Public License
    16  // along with Gauge.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package validation
    19  
    20  import (
    21  	"net"
    22  	"testing"
    23  
    24  	"github.com/getgauge/gauge/gauge"
    25  	"github.com/getgauge/gauge/gauge_messages"
    26  	"github.com/getgauge/gauge/parser"
    27  
    28  	"errors"
    29  
    30  	"bytes"
    31  
    32  	. "gopkg.in/check.v1"
    33  )
    34  
    35  func Test(t *testing.T) { TestingT(t) }
    36  
    37  type MySuite struct{}
    38  
    39  var _ = Suite(&MySuite{})
    40  
    41  func (s *MySuite) TestSkipSpecIfAllScenariosAreSkipped(c *C) {
    42  	specText := `Specification Heading
    43  =====================
    44  Scenario 1
    45  ----------
    46  * say hello1
    47  
    48  Scenario 2
    49  ----------
    50  * say hello2
    51  `
    52  	p := new(parser.SpecParser)
    53  	spec, _, _ := p.Parse(specText, gauge.NewConceptDictionary(), "")
    54  	err := gauge_messages.StepValidateResponse_STEP_IMPLEMENTATION_NOT_FOUND
    55  	errs := validationErrors{spec: []error{
    56  		NewStepValidationError(spec.Scenarios[0].Steps[0], "", "", &err, ""),
    57  		NewStepValidationError(spec.Scenarios[1].Steps[0], "", "", &err, ""),
    58  	}}
    59  
    60  	errMap := getErrMap(gauge.NewBuildErrors(), errs)
    61  
    62  	c.Assert(len(errMap.SpecErrs), Equals, 1)
    63  	c.Assert(len(errMap.ScenarioErrs), Equals, 2)
    64  	c.Assert(len(errMap.StepErrs), Equals, 2)
    65  }
    66  
    67  func (s *MySuite) TestDoesNotSkipSpecIfAllScenariosAreNotSkipped(c *C) {
    68  	specText := `Specification Heading
    69  =====================
    70  Scenario 1
    71  ----------
    72  * say hello1
    73  
    74  Scenario 2
    75  ----------
    76  * say hello2
    77  `
    78  	p := new(parser.SpecParser)
    79  	spec, _, _ := p.Parse(specText, gauge.NewConceptDictionary(), "")
    80  	err := gauge_messages.StepValidateResponse_STEP_IMPLEMENTATION_NOT_FOUND
    81  
    82  	errs := validationErrors{spec: []error{
    83  		NewStepValidationError(spec.Scenarios[0].Steps[0], "", "", &err, ""),
    84  	}}
    85  
    86  	errMap := getErrMap(gauge.NewBuildErrors(), errs)
    87  
    88  	c.Assert(len(errMap.SpecErrs), Equals, 0)
    89  	c.Assert(len(errMap.ScenarioErrs), Equals, 1)
    90  	c.Assert(len(errMap.StepErrs), Equals, 1)
    91  }
    92  
    93  func (s *MySuite) TestSkipSpecIfNoScenariosPresent(c *C) {
    94  	specText := `Specification Heading
    95  =====================
    96  * say hello1
    97  * say hello2
    98  `
    99  	p := new(parser.SpecParser)
   100  	spec, _, _ := p.Parse(specText, gauge.NewConceptDictionary(), "")
   101  
   102  	errs := validationErrors{spec: []error{}}
   103  
   104  	errMap := getErrMap(gauge.NewBuildErrors(), errs)
   105  
   106  	c.Assert(len(errMap.SpecErrs), Equals, 0)
   107  	c.Assert(len(errMap.ScenarioErrs), Equals, 0)
   108  	c.Assert(len(errMap.StepErrs), Equals, 0)
   109  }
   110  
   111  func (s *MySuite) TestSkipSpecIfTableRowOutOfRange(c *C) {
   112  	specText := `Specification Heading
   113  =====================
   114  Scenario 1
   115  ----------
   116  * say hello1
   117  
   118  Scenario 2
   119  ----------
   120  * say hello2
   121  `
   122  	p := new(parser.SpecParser)
   123  	spec, _, _ := p.Parse(specText, gauge.NewConceptDictionary(), "")
   124  
   125  	errs := validationErrors{spec: []error{
   126  		NewSpecValidationError("Table row out of range", spec.FileName),
   127  	}}
   128  
   129  	errMap := getErrMap(gauge.NewBuildErrors(), errs)
   130  
   131  	c.Assert(len(errMap.SpecErrs), Equals, 1)
   132  	c.Assert(len(errMap.ScenarioErrs), Equals, 0)
   133  	c.Assert(len(errMap.StepErrs), Equals, 0)
   134  }
   135  
   136  func (s *MySuite) TestValidateStep(c *C) {
   137  	HideSuggestion = false
   138  	var suggestion bytes.Buffer
   139  	myStep := &gauge.Step{Value: "my step", LineText: "my step", IsConcept: false, LineNo: 3}
   140  	runner := &mockRunner{
   141  		ExecuteMessageFunc: func(m *gauge_messages.Message) (*gauge_messages.Message, error) {
   142  			suggestion.WriteString("\n\t@Step(\"my step\")\n\tpublic void implementation1(){\n\t\t// your code here...\n\t}")
   143  			res := &gauge_messages.StepValidateResponse{IsValid: false, ErrorMessage: "my err msg", ErrorType: gauge_messages.StepValidateResponse_STEP_IMPLEMENTATION_NOT_FOUND, Suggestion: suggestion.String()}
   144  			return &gauge_messages.Message{MessageType: gauge_messages.Message_StepValidateResponse, StepValidateResponse: res}, nil
   145  		},
   146  	}
   147  	specVal := &SpecValidator{specification: &gauge.Specification{FileName: "foo.spec"}, runner: runner}
   148  	valErr := specVal.validateStep(myStep)
   149  
   150  	c.Assert(valErr, Not(Equals), nil)
   151  	c.Assert(valErr.Error(), Equals, "foo.spec:3 Step implementation not found => 'my step'")
   152  	c.Assert(valErr.(StepValidationError).Suggestion(), Equals, "\n\t"+
   153  		"@Step(\"my step\")\n\t"+
   154  		"public void implementation1(){\n\t"+
   155  		"\t// your code here...\n\t"+
   156  		"}")
   157  }
   158  
   159  func (s *MySuite) TestShouldNotGiveSuggestionWhenHideSuggestionFlagIsFalse(c *C) {
   160  	HideSuggestion = true
   161  	myStep := &gauge.Step{Value: "my step", LineText: "my step", IsConcept: false, LineNo: 3}
   162  	runner := &mockRunner{
   163  		ExecuteMessageFunc: func(m *gauge_messages.Message) (*gauge_messages.Message, error) {
   164  			res := &gauge_messages.StepValidateResponse{IsValid: false, ErrorMessage: "my err msg", ErrorType: gauge_messages.StepValidateResponse_STEP_IMPLEMENTATION_NOT_FOUND}
   165  			return &gauge_messages.Message{MessageType: gauge_messages.Message_StepValidateResponse, StepValidateResponse: res}, nil
   166  		},
   167  	}
   168  	specVal := &SpecValidator{specification: &gauge.Specification{FileName: "foo.spec"}, runner: runner}
   169  	valErr := specVal.validateStep(myStep)
   170  
   171  	c.Assert(valErr, Not(Equals), nil)
   172  	c.Assert(valErr.Error(), Equals, "foo.spec:3 Step implementation not found => 'my step'")
   173  	c.Assert(valErr.(StepValidationError).suggestion, Equals, "")
   174  }
   175  
   176  func (s *MySuite) TestValidateStepInConcept(c *C) {
   177  	HideSuggestion = false
   178  	var suggestion bytes.Buffer
   179  	parentStep := &gauge.Step{Value: "my concept", LineNo: 2, IsConcept: true, LineText: "my concept"}
   180  	myStep := &gauge.Step{Value: "my step", LineText: "my step", IsConcept: false, LineNo: 3, Parent: parentStep}
   181  	cptDict := gauge.NewConceptDictionary()
   182  	cptDict.ConceptsMap["my concept"] = &gauge.Concept{ConceptStep: parentStep, FileName: "concept.cpt"}
   183  	runner := &mockRunner{
   184  		ExecuteMessageFunc: func(m *gauge_messages.Message) (*gauge_messages.Message, error) {
   185  			suggestion.WriteString("\n\t@Step(\"my step\")\n\tpublic void implementation1(){\n\t\t// your code here...\n\t}")
   186  			res := &gauge_messages.StepValidateResponse{IsValid: false, ErrorMessage: "my err msg", ErrorType: gauge_messages.StepValidateResponse_STEP_IMPLEMENTATION_NOT_FOUND, Suggestion: suggestion.String()}
   187  			return &gauge_messages.Message{MessageType: gauge_messages.Message_StepValidateResponse, StepValidateResponse: res}, nil
   188  		},
   189  	}
   190  
   191  	specVal := &SpecValidator{specification: &gauge.Specification{FileName: "foo.spec"}, conceptsDictionary: cptDict, runner: runner}
   192  	valErr := specVal.validateStep(myStep)
   193  
   194  	c.Assert(valErr, Not(Equals), nil)
   195  	c.Assert(valErr.Error(), Equals, "concept.cpt:3 Step implementation not found => 'my step'")
   196  	c.Assert(valErr.(StepValidationError).Suggestion(), Equals, "\n\t@Step(\"my step\")\n\t"+
   197  		"public void implementation1(){\n\t"+
   198  		"\t// your code here...\n\t"+
   199  		"}")
   200  }
   201  
   202  func (s *MySuite) TestFilterDuplicateValidationErrors(c *C) {
   203  	specText := `Specification Heading
   204  =====================
   205  Scenario 1
   206  ----------
   207  * abc
   208  
   209  Scenario 2
   210  ----------
   211  * hello
   212  `
   213  	step := gauge.Step{
   214  		Value: "abc",
   215  	}
   216  	step1 := gauge.Step{
   217  		Value: "helo",
   218  	}
   219  	implNotFoundError := StepValidationError{
   220  		step:       &step,
   221  		errorType:  &implNotFound,
   222  		suggestion: "suggestion",
   223  	}
   224  	dupImplFoundError := StepValidationError{
   225  		step:       &step1,
   226  		errorType:  &dupImplFound,
   227  		suggestion: "suggestion1",
   228  	}
   229  
   230  	p := new(parser.SpecParser)
   231  	spec, _, _ := p.Parse(specText, gauge.NewConceptDictionary(), "")
   232  
   233  	errs := validationErrors{spec: []error{
   234  		implNotFoundError,
   235  		implNotFoundError,
   236  		dupImplFoundError,
   237  	}}
   238  
   239  	want := []error{implNotFoundError, dupImplFoundError}
   240  
   241  	got := FilterDuplicates(errs)
   242  
   243  	c.Assert(got, DeepEquals, want)
   244  }
   245  
   246  type tableRow struct {
   247  	name           string
   248  	input          string
   249  	tableRowsCount int
   250  	err            error
   251  }
   252  
   253  var tableRowTests = []*tableRow{
   254  	{"Valid single row number", "3", 5, nil},
   255  	{"Invalid single row number", "2", 1, errors.New("Table rows range validation failed => Table row number '2' is out of range")},
   256  	{"Valid row numbers list", "2,3,4", 4, nil},
   257  	{"Invalid list with empty value", ",3,4", 4, errors.New("Table rows range validation failed => Row number cannot be empty")},
   258  	{"Invalid row numbers list", "2,3,4", 3, errors.New("Table rows range validation failed => Table row number '4' is out of range")},
   259  	{"Invalid row numbers list with special chars", "2*&", 3, errors.New("Table rows range validation failed => Failed to parse '2*&' to row number")},
   260  	{"Valid table rows range", "2-5", 5, nil},
   261  	{"Invalid table rows range", "2-5", 4, errors.New("Table rows range validation failed => Table row number '5' is out of range")},
   262  	{"Invalid table rows range", "2-2", 4, nil},
   263  	{"Invalid table rows with character", "a", 4, errors.New("Table rows range validation failed => Failed to parse 'a' to row number")},
   264  	{"Invalid table rows range with character", "a-5", 5, errors.New("Table rows range validation failed => Failed to parse 'a' to row number")},
   265  	{"Invalid table rows range with string", "a-qwerty", 4, errors.New("Table rows range validation failed => Failed to parse 'a' to row number")},
   266  	{"Empty table rows range", "", 4, nil},
   267  	{"Table rows range with multiple -", "2-3-4", 4, errors.New("Table rows range '2-3-4' is invalid => Table rows range should be of format rowNumber-rowNumber")},
   268  	{"Table rows range with different separator", "2:4", 4, errors.New("Table rows range validation failed => Failed to parse '2:4' to row number")},
   269  	{"Table rows list with spaces", "2, 4 ", 4, nil},
   270  	{"Row count is zero with empty input", "", 0, nil},
   271  	{"Row count is zero with non empty input", "1", 0, errors.New("Table rows range validation failed => Table row number '1' is out of range")},
   272  	{"Row count is non-zero with empty input", "", 2, nil},
   273  	{"Row count is non-zero with non-empty input", "2", 2, nil},
   274  }
   275  
   276  func (s *MySuite) TestToValidateDataTableRowsRangeFromInputFlag(c *C) {
   277  	for _, test := range tableRowTests {
   278  		TableRows = test.input
   279  		got := validateDataTableRange(test.tableRowsCount)
   280  		want := test.err
   281  		c.Assert(got, DeepEquals, want, Commentf(test.name))
   282  	}
   283  }
   284  
   285  type mockRunner struct {
   286  	ExecuteMessageFunc func(m *gauge_messages.Message) (*gauge_messages.Message, error)
   287  }
   288  
   289  func (r *mockRunner) ExecuteMessageWithTimeout(m *gauge_messages.Message) (*gauge_messages.Message, error) {
   290  	return r.ExecuteMessageFunc(m)
   291  }
   292  func (r *mockRunner) ExecuteAndGetStatus(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult {
   293  	return nil
   294  }
   295  
   296  func (r *mockRunner) Alive() bool {
   297  	return false
   298  }
   299  
   300  func (r *mockRunner) Kill() error {
   301  	return nil
   302  }
   303  
   304  func (r *mockRunner) Connection() net.Conn {
   305  	return nil
   306  }
   307  
   308  func (r *mockRunner) IsMultithreaded() bool {
   309  	return false
   310  }
   311  
   312  func (r *mockRunner) Pid() int {
   313  	return -1
   314  }