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