github.com/ezbuy/gauge@v0.9.4-0.20171013092048-7ac5bd3931cd/parser/conceptParser_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 parser
    19  
    20  import (
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	"github.com/getgauge/gauge/config"
    25  	"github.com/getgauge/gauge/gauge"
    26  	. "gopkg.in/check.v1"
    27  )
    28  
    29  func assertStepEqual(c *C, expected, actual *gauge.Step) {
    30  	c.Assert(expected.LineNo, Equals, actual.LineNo)
    31  	c.Assert(expected.Value, Equals, actual.Value)
    32  	c.Assert(expected.LineText, Equals, actual.LineText)
    33  }
    34  
    35  func (s *MySuite) TearDownTest(c *C) {
    36  	config.ProjectRoot = ""
    37  }
    38  
    39  func (s *MySuite) TestConceptDictionaryAdd(c *C) {
    40  	dictionary := gauge.NewConceptDictionary()
    41  	step1Text := "test concept step 1"
    42  	step2Text := "test concept step 2"
    43  	step1 := &gauge.Step{Value: step1Text, LineNo: 1, IsConcept: true, LineText: step1Text}
    44  	step2 := &gauge.Step{Value: step2Text, LineNo: 4, IsConcept: true, LineText: step2Text}
    45  	path, _ := filepath.Abs(filepath.Join("testdata", "concept.cpt"))
    46  
    47  	concepts, errs := AddConcepts([]string{path}, dictionary)
    48  
    49  	c.Assert(len(concepts), Equals, 2)
    50  	c.Assert(len(errs), Equals, 0)
    51  	assertStepEqual(c, dictionary.ConceptsMap[step1Text].ConceptStep, step1)
    52  	c.Assert(dictionary.ConceptsMap[step1Text].FileName, Equals, path)
    53  	assertStepEqual(c, dictionary.ConceptsMap[step2Text].ConceptStep, step2)
    54  	c.Assert(dictionary.ConceptsMap[step2Text].FileName, Equals, path)
    55  }
    56  
    57  func (s *MySuite) TestConceptDictionaryAddDuplicateConcept(c *C) {
    58  	dictionary := gauge.NewConceptDictionary()
    59  	path, _ := filepath.Abs(filepath.Join("testdata", "err", "cpt", "duplicate_concept.cpt"))
    60  
    61  	concepts, errs := AddConcepts([]string{path}, dictionary)
    62  
    63  	c.Assert(len(concepts), Equals, 2)
    64  	c.Assert(len(errs) > 0, Equals, true)
    65  	if !(hasParseError("Duplicate concept definition found => 'test concept step 5' => at\n\t"+path+":4\n\t"+path+":1", errs) ||
    66  		hasParseError("Duplicate concept definition found => 'test concept step 5' => at\n\t"+path+":1\n\t"+path+":4", errs)) {
    67  		c.Fail()
    68  	}
    69  }
    70  
    71  func hasParseError(eMessage string, errs []ParseError) bool {
    72  	for _, e := range errs {
    73  		if e.Message == eMessage {
    74  			return true
    75  		}
    76  	}
    77  	return false
    78  }
    79  
    80  func (s *MySuite) TestDuplicateConceptsinMultipleFile(c *C) {
    81  	dictionary := gauge.NewConceptDictionary()
    82  	cpt1, _ := filepath.Abs(filepath.Join("testdata", "err", "cpt", "concept.cpt"))
    83  	cpt2, _ := filepath.Abs(filepath.Join("testdata", "err", "cpt", "duplicate.cpt"))
    84  
    85  	AddConcepts([]string{cpt1}, dictionary)
    86  	concepts, errs := AddConcepts([]string{cpt2}, dictionary)
    87  
    88  	c.Assert(len(concepts), Equals, 2)
    89  	c.Assert(len(errs), Equals, 2)
    90  	if !(hasParseError("Duplicate concept definition found => 'test concept step 1' => at\n\t"+cpt2+":1\n\t"+cpt1+":1", errs) ||
    91  		hasParseError("Duplicate concept definition found => 'test concept step 1' => at\n\t"+cpt1+":1\n\t"+cpt2+":1", errs)) {
    92  		c.Fail()
    93  	}
    94  }
    95  
    96  func (s *MySuite) TestCreateConceptDictionaryGivesAllParseErrors(c *C) {
    97  	config.ProjectRoot, _ = filepath.Abs(filepath.Join("testdata", "err", "cpt"))
    98  
    99  	_, res := CreateConceptsDictionary()
   100  
   101  	c.Assert(res.Ok, Equals, false)
   102  	c.Assert(len(res.ParseErrors), Equals, 5)
   103  }
   104  
   105  func (s *MySuite) TestCreateConceptDictionary(c *C) {
   106  	config.ProjectRoot, _ = filepath.Abs(filepath.Join("testdata", "dir1"))
   107  
   108  	dict, res := CreateConceptsDictionary()
   109  
   110  	c.Assert(res.Ok, Equals, true)
   111  	c.Assert(dict, NotNil)
   112  	c.Assert(len(dict.ConceptsMap), Equals, 1)
   113  }
   114  
   115  func (s *MySuite) TestConceptDictionaryWithNestedConcepts(c *C) {
   116  	dictionary := gauge.NewConceptDictionary()
   117  	path, _ := filepath.Abs(filepath.Join("testdata", "nested_concept.cpt"))
   118  
   119  	AddConcepts([]string{path}, dictionary)
   120  	concept := dictionary.Search("test concept step 1")
   121  
   122  	c.Assert(len(concept.ConceptStep.ConceptSteps), Equals, 1)
   123  
   124  	actualNestedConcept := concept.ConceptStep.ConceptSteps[0]
   125  	c.Assert(actualNestedConcept.IsConcept, Equals, true)
   126  	c.Assert(len(actualNestedConcept.ConceptSteps), Equals, 1)
   127  	c.Assert(actualNestedConcept.ConceptSteps[0].Value, Equals, "step 2")
   128  }
   129  
   130  func (s *MySuite) TestConceptDictionaryWithNestedConceptsWithDynamicParameters(c *C) {
   131  	conceptDictionary := gauge.NewConceptDictionary()
   132  	path, _ := filepath.Abs(filepath.Join("testdata", "dynamic_param_concept.cpt"))
   133  
   134  	AddConcepts([]string{path}, conceptDictionary)
   135  	concept := conceptDictionary.Search("create user {} {} and {}")
   136  	c.Assert(len(concept.ConceptStep.ConceptSteps), Equals, 1)
   137  	actualNestedConcept := concept.ConceptStep.ConceptSteps[0]
   138  	c.Assert(actualNestedConcept.IsConcept, Equals, true)
   139  
   140  	c.Assert(len(actualNestedConcept.ConceptSteps), Equals, 2)
   141  	c.Assert(actualNestedConcept.ConceptSteps[0].Value, Equals, "add id {}")
   142  	c.Assert(actualNestedConcept.ConceptSteps[0].Args[0].ArgType, Equals, gauge.Dynamic)
   143  	c.Assert(actualNestedConcept.ConceptSteps[0].Args[0].Value, Equals, "userid")
   144  
   145  	c.Assert(actualNestedConcept.ConceptSteps[1].Value, Equals, "add name {}")
   146  	c.Assert(actualNestedConcept.ConceptSteps[1].Args[0].ArgType, Equals, gauge.Dynamic)
   147  	c.Assert(actualNestedConcept.ConceptSteps[1].Args[0].Value, Equals, "username")
   148  }
   149  
   150  func (s *MySuite) TestConceptDictionaryWithNestedConceptsWithStaticParameters(c *C) {
   151  	conceptDictionary := gauge.NewConceptDictionary()
   152  	path, _ := filepath.Abs(filepath.Join("testdata", "static_param_concept.cpt"))
   153  
   154  	AddConcepts([]string{path}, conceptDictionary)
   155  	concept := conceptDictionary.Search("create user {} {} and {}")
   156  	c.Assert(len(concept.ConceptStep.ConceptSteps), Equals, 2)
   157  	actualNestedConcept := concept.ConceptStep.ConceptSteps[0]
   158  	c.Assert(actualNestedConcept.IsConcept, Equals, true)
   159  
   160  	c.Assert(actualNestedConcept.Args[0].ArgType, Equals, gauge.Dynamic)
   161  	c.Assert(actualNestedConcept.Args[0].Value, Equals, "user-id")
   162  
   163  	c.Assert(actualNestedConcept.Args[1].ArgType, Equals, gauge.Static)
   164  	c.Assert(actualNestedConcept.Args[1].Value, Equals, "static-value")
   165  	c.Assert(actualNestedConcept.Lookup.GetArg("userid").Value, Equals, "user-id")
   166  	c.Assert(actualNestedConcept.Lookup.GetArg("userid").ArgType, Equals, gauge.Dynamic)
   167  	c.Assert(actualNestedConcept.Lookup.GetArg("username").Value, Equals, "static-value")
   168  	c.Assert(actualNestedConcept.Lookup.GetArg("username").ArgType, Equals, gauge.Static)
   169  
   170  	c.Assert(len(actualNestedConcept.ConceptSteps), Equals, 2)
   171  	c.Assert(actualNestedConcept.ConceptSteps[0].Value, Equals, "add id {}")
   172  	c.Assert(actualNestedConcept.ConceptSteps[0].Args[0].ArgType, Equals, gauge.Dynamic)
   173  	c.Assert(actualNestedConcept.ConceptSteps[0].Args[0].Value, Equals, "userid")
   174  
   175  	c.Assert(actualNestedConcept.ConceptSteps[1].Value, Equals, "add name {}")
   176  	c.Assert(actualNestedConcept.ConceptSteps[1].Args[0].ArgType, Equals, gauge.Dynamic)
   177  	c.Assert(actualNestedConcept.ConceptSteps[1].Args[0].Value, Equals, "username")
   178  }
   179  
   180  func (s *MySuite) TestConceptHavingItemsWithComments(c *C) {
   181  	conceptDictionary := gauge.NewConceptDictionary()
   182  	path, _ := filepath.Abs(filepath.Join("testdata", "dynamic_param_concept.cpt"))
   183  
   184  	AddConcepts([]string{path}, conceptDictionary)
   185  	concept := conceptDictionary.Search("create user {} {} and {}")
   186  
   187  	c.Assert(len(concept.ConceptStep.Items), Equals, 3)
   188  	c.Assert(concept.ConceptStep.Items[2].(*gauge.Comment).Value, Equals, "Comments")
   189  
   190  	concept = conceptDictionary.Search("assign id {} and name {}")
   191  
   192  	c.Assert(len(concept.ConceptStep.Items), Equals, 4)
   193  	c.Assert(concept.ConceptStep.Items[3].(*gauge.Comment).Value, Equals, "Comment1")
   194  }
   195  
   196  func (s *MySuite) TestConceptHavingItemsWithTablesAndComments(c *C) {
   197  	conceptDictionary := gauge.NewConceptDictionary()
   198  	path, _ := filepath.Abs(filepath.Join("testdata", "tabular_concept.cpt"))
   199  
   200  	AddConcepts([]string{path}, conceptDictionary)
   201  
   202  	concept := conceptDictionary.Search("my concept {}")
   203  	c.Assert(len(concept.ConceptStep.Items), Equals, 3)
   204  	c.Assert(len(concept.ConceptStep.PreComments), Equals, 1)
   205  	c.Assert(concept.ConceptStep.PreComments[0].Value, Equals, "COMMENT")
   206  	c.Assert(concept.ConceptStep.Items[2].(*gauge.Comment).Value, Equals, "   comment")
   207  }
   208  
   209  func (s *MySuite) TestMultiLevelConcept(c *C) {
   210  	conceptDictionary := gauge.NewConceptDictionary()
   211  	path, _ := filepath.Abs(filepath.Join("testdata", "nested_concept2.cpt"))
   212  
   213  	AddConcepts([]string{path}, conceptDictionary)
   214  	actualTopLevelConcept := conceptDictionary.Search("top level concept")
   215  	c.Assert(len(actualTopLevelConcept.ConceptStep.ConceptSteps), Equals, 2)
   216  	actualNestedConcept := actualTopLevelConcept.ConceptStep.ConceptSteps[0]
   217  	c.Assert(actualNestedConcept.IsConcept, Equals, true)
   218  	c.Assert(len(actualNestedConcept.ConceptSteps), Equals, 2)
   219  	c.Assert(actualNestedConcept.ConceptSteps[0].Value, Equals, "another nested concept")
   220  	c.Assert(actualNestedConcept.ConceptSteps[1].Value, Equals, "normal step 2")
   221  	c.Assert(actualTopLevelConcept.ConceptStep.ConceptSteps[1].Value, Equals, "normal step 1")
   222  
   223  	actualAnotherNestedConcept := conceptDictionary.Search("another nested concept")
   224  	c.Assert(len(actualAnotherNestedConcept.ConceptStep.ConceptSteps), Equals, 1)
   225  	step := actualAnotherNestedConcept.ConceptStep.ConceptSteps[0]
   226  	c.Assert(step.IsConcept, Equals, false)
   227  	c.Assert(step.Value, Equals, "normal step 3")
   228  
   229  	nestedConcept2 := conceptDictionary.Search("nested concept")
   230  	c.Assert(len(nestedConcept2.ConceptStep.ConceptSteps), Equals, 2)
   231  	actualAnotherNestedConcept2 := nestedConcept2.ConceptStep.ConceptSteps[0]
   232  	c.Assert(actualAnotherNestedConcept2.IsConcept, Equals, true)
   233  	c.Assert(len(actualAnotherNestedConcept2.ConceptSteps), Equals, 1)
   234  	c.Assert(actualAnotherNestedConcept2.ConceptSteps[0].Value, Equals, "normal step 3")
   235  	c.Assert(nestedConcept2.ConceptStep.ConceptSteps[1].Value, Equals, "normal step 2")
   236  }
   237  
   238  func (s *MySuite) TestParsingSimpleConcept(c *C) {
   239  	parser := new(ConceptParser)
   240  	concepts, parseRes := parser.Parse("# my concept \n * first step \n * second step ", "")
   241  
   242  	c.Assert(len(parseRes.ParseErrors), Equals, 0)
   243  	c.Assert(len(concepts), Equals, 1)
   244  
   245  	concept := concepts[0]
   246  
   247  	c.Assert(concept.IsConcept, Equals, true)
   248  	c.Assert(len(concept.ConceptSteps), Equals, 2)
   249  	c.Assert(concept.ConceptSteps[0].Value, Equals, "first step")
   250  	c.Assert(concept.ConceptSteps[1].Value, Equals, "second step")
   251  }
   252  
   253  func (s *MySuite) TestParsingConceptRetainsStepSuffix(c *C) {
   254  	parser := new(ConceptParser)
   255  	concepts, parseRes := parser.Parse("# my concept \n * first step \n * second step \n\n", "")
   256  
   257  	c.Assert(len(parseRes.ParseErrors), Equals, 0)
   258  	c.Assert(len(concepts), Equals, 1)
   259  
   260  	concept := concepts[0]
   261  
   262  	c.Assert(concept.IsConcept, Equals, true)
   263  	c.Assert(len(concept.ConceptSteps), Equals, 2)
   264  	c.Assert(concept.ConceptSteps[0].Value, Equals, "first step")
   265  	c.Assert(concept.ConceptSteps[1].Value, Equals, "second step")
   266  	c.Assert(concept.ConceptSteps[0].Suffix, Equals, "")
   267  	c.Assert(concept.ConceptSteps[1].Suffix, Equals, "\n")
   268  }
   269  
   270  func (s *MySuite) TestErrorParsingConceptHeadingWithStaticOrSpecialParameter(c *C) {
   271  	parser := new(ConceptParser)
   272  	_, parseRes := parser.Parse("# my concept with \"parameter\" \n * first step \n * second step ", "foo.spec")
   273  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   274  	c.Assert(parseRes.ParseErrors[0].Error(), Equals, "foo.spec:1 Concept heading can have only Dynamic Parameters => 'my concept with \"parameter\"'")
   275  
   276  	_, parseRes = parser.Parse("# my concept with <table: foo> \n * first step \n * second step ", "foo2.spec")
   277  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   278  	c.Assert(parseRes.ParseErrors[0].Error(), Equals, "foo2.spec:1 Dynamic parameter <table: foo> could not be resolved => 'my concept with <table: foo>'")
   279  }
   280  
   281  func (s *MySuite) TestErrorParsingConceptWithoutHeading(c *C) {
   282  	parser := new(ConceptParser)
   283  
   284  	_, parseRes := parser.Parse("* first step \n * second step ", "")
   285  
   286  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   287  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Step is not defined inside a concept heading")
   288  }
   289  
   290  func (s *MySuite) TestErrorParsingConceptWithoutSteps(c *C) {
   291  	parser := new(ConceptParser)
   292  
   293  	_, parseRes := parser.Parse("# my concept with \n", "")
   294  
   295  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   296  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Concept should have atleast one step")
   297  }
   298  
   299  func (s *MySuite) TestParsingSimpleConceptWithParameters(c *C) {
   300  	parser := new(ConceptParser)
   301  	concepts, parseRes := parser.Parse("# my concept with <param0> and <param1> \n * first step using <param0> \n * second step using \"value\" and <param1> ", "")
   302  
   303  	c.Assert(len(parseRes.ParseErrors), Equals, 0)
   304  	c.Assert(len(concepts), Equals, 1)
   305  
   306  	concept := concepts[0]
   307  	c.Assert(concept.IsConcept, Equals, true)
   308  	c.Assert(len(concept.ConceptSteps), Equals, 2)
   309  	// c.Assert(len(concept.Lookup.paramValue), Equals, 2)
   310  	c.Assert(concept.Lookup.ContainsArg("param0"), Equals, true)
   311  	c.Assert(concept.Lookup.ContainsArg("param1"), Equals, true)
   312  
   313  	firstConcept := concept.ConceptSteps[0]
   314  	c.Assert(firstConcept.Value, Equals, "first step using {}")
   315  	c.Assert(len(firstConcept.Args), Equals, 1)
   316  	c.Assert(firstConcept.Args[0].ArgType, Equals, gauge.Dynamic)
   317  	c.Assert(firstConcept.Args[0].Value, Equals, "param0")
   318  
   319  	secondConcept := concept.ConceptSteps[1]
   320  	c.Assert(secondConcept.Value, Equals, "second step using {} and {}")
   321  	c.Assert(len(secondConcept.Args), Equals, 2)
   322  	c.Assert(secondConcept.Args[0].ArgType, Equals, gauge.Static)
   323  	c.Assert(secondConcept.Args[0].Value, Equals, "value")
   324  	c.Assert(secondConcept.Args[1].ArgType, Equals, gauge.Dynamic)
   325  	c.Assert(secondConcept.Args[1].Value, Equals, "param1")
   326  
   327  }
   328  
   329  func (s *MySuite) TestErrorParsingConceptStepWithInvalidParameters(c *C) {
   330  	parser := new(ConceptParser)
   331  	_, parseRes := parser.Parse("# my concept with <param0> and <param1> \n * first step using <param3> \n * second step using \"value\" and <param1> ", "")
   332  
   333  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   334  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Dynamic parameter <param3> could not be resolved")
   335  }
   336  
   337  func (s *MySuite) TestParsingMultipleConcept(c *C) {
   338  	parser := new(ConceptParser)
   339  	concepts, parseRes := parser.Parse("# my concept \n * first step \n * second step \n# my second concept \n* next step\n # my third concept <param0>\n * next step <param0> and \"value\"\n  ", "")
   340  
   341  	c.Assert(len(parseRes.ParseErrors), Equals, 0)
   342  	c.Assert(len(concepts), Equals, 3)
   343  
   344  	firstConcept := concepts[0]
   345  	secondConcept := concepts[1]
   346  	thirdConcept := concepts[2]
   347  
   348  	c.Assert(firstConcept.IsConcept, Equals, true)
   349  	c.Assert(len(firstConcept.ConceptSteps), Equals, 2)
   350  	c.Assert(firstConcept.ConceptSteps[0].Value, Equals, "first step")
   351  	c.Assert(firstConcept.ConceptSteps[1].Value, Equals, "second step")
   352  
   353  	c.Assert(secondConcept.IsConcept, Equals, true)
   354  	c.Assert(len(secondConcept.ConceptSteps), Equals, 1)
   355  	c.Assert(secondConcept.ConceptSteps[0].Value, Equals, "next step")
   356  
   357  	c.Assert(thirdConcept.IsConcept, Equals, true)
   358  	c.Assert(len(thirdConcept.ConceptSteps), Equals, 1)
   359  	c.Assert(thirdConcept.ConceptSteps[0].Value, Equals, "next step {} and {}")
   360  	c.Assert(len(thirdConcept.ConceptSteps[0].Args), Equals, 2)
   361  	c.Assert(thirdConcept.ConceptSteps[0].Args[0].ArgType, Equals, gauge.Dynamic)
   362  	c.Assert(thirdConcept.ConceptSteps[0].Args[1].ArgType, Equals, gauge.Static)
   363  
   364  	// c.Assert(len(thirdConcept.Lookup.paramValue), Equals, 1)
   365  	c.Assert(thirdConcept.Lookup.ContainsArg("param0"), Equals, true)
   366  
   367  }
   368  
   369  func (s *MySuite) TestParsingConceptStepWithInlineTable(c *C) {
   370  	parser := new(ConceptParser)
   371  	concepts, parseRes := parser.Parse("# my concept <foo> \n * first step with <foo> and inline table\n |id|name|\n|1|vishnu|\n|2|prateek|\n", "")
   372  
   373  	c.Assert(len(parseRes.ParseErrors), Equals, 0)
   374  	c.Assert(len(concepts), Equals, 1)
   375  
   376  	concept := concepts[0]
   377  
   378  	c.Assert(concept.IsConcept, Equals, true)
   379  	c.Assert(len(concept.ConceptSteps), Equals, 1)
   380  	c.Assert(concept.ConceptSteps[0].Value, Equals, "first step with {} and inline table {}")
   381  
   382  	tableArgument := concept.ConceptSteps[0].Args[1]
   383  	c.Assert(tableArgument.ArgType, Equals, gauge.TableArg)
   384  
   385  	inlineTable := tableArgument.Table
   386  	c.Assert(inlineTable.IsInitialized(), Equals, true)
   387  	c.Assert(len(inlineTable.Get("id")), Equals, 2)
   388  	c.Assert(len(inlineTable.Get("name")), Equals, 2)
   389  	c.Assert(inlineTable.Get("id")[0].Value, Equals, "1")
   390  	c.Assert(inlineTable.Get("id")[0].CellType, Equals, gauge.Static)
   391  	c.Assert(inlineTable.Get("id")[1].Value, Equals, "2")
   392  	c.Assert(inlineTable.Get("id")[1].CellType, Equals, gauge.Static)
   393  	c.Assert(inlineTable.Get("name")[0].Value, Equals, "vishnu")
   394  	c.Assert(inlineTable.Get("name")[0].CellType, Equals, gauge.Static)
   395  	c.Assert(inlineTable.Get("name")[1].Value, Equals, "prateek")
   396  	c.Assert(inlineTable.Get("name")[1].CellType, Equals, gauge.Static)
   397  }
   398  
   399  func (s *MySuite) TestErrorParsingConceptWithInvalidInlineTable(c *C) {
   400  	parser := new(ConceptParser)
   401  	_, parseRes := parser.Parse("# my concept \n |id|name|\n|1|vishnu|\n|2|prateek|\n", "")
   402  
   403  	c.Assert(len(parseRes.ParseErrors), Not(Equals), 0)
   404  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Table doesn't belong to any step")
   405  }
   406  
   407  func (s *MySuite) TestNestedConceptLooksUpArgsFromParent(c *C) {
   408  	parser := new(SpecParser)
   409  	specText := SpecBuilder().specHeading("A spec heading").
   410  		scenarioHeading("First flow").
   411  		step("create user \"foo\" \"doo\"").
   412  		step("another step").String()
   413  
   414  	dictionary := gauge.NewConceptDictionary()
   415  	path, _ := filepath.Abs(filepath.Join("testdata", "param_nested_concept.cpt"))
   416  
   417  	AddConcepts([]string{path}, dictionary)
   418  	tokens, _ := parser.GenerateTokens(specText, "")
   419  	spec, parseResult := parser.CreateSpecification(tokens, dictionary, "")
   420  
   421  	c.Assert(parseResult.Ok, Equals, true)
   422  	firstStepInSpec := spec.Scenarios[0].Steps[0]
   423  	nestedConcept := firstStepInSpec.ConceptSteps[0]
   424  	nestedConceptArg1 := nestedConcept.GetArg("baz")
   425  	c.Assert(nestedConceptArg1.Value, Equals, "foo")
   426  	nestedConceptArg2 := nestedConcept.GetArg("boo")
   427  	c.Assert(nestedConceptArg2.Value, Equals, "doo")
   428  }
   429  
   430  func (s *MySuite) TestNestedConceptLooksUpDataTableArgs(c *C) {
   431  	parser := new(SpecParser)
   432  	specText := SpecBuilder().specHeading("A spec heading").
   433  		tableHeader("id", "name", "phone").
   434  		tableHeader("123", "prateek", "8800").
   435  		tableHeader("456", "apoorva", "9800").
   436  		tableHeader("789", "srikanth", "7900").
   437  		scenarioHeading("First scenario").
   438  		step("create user <id> <name>").
   439  		step("another step").String()
   440  
   441  	dictionary := gauge.NewConceptDictionary()
   442  	path, _ := filepath.Abs(filepath.Join("testdata", "param_nested_concept.cpt"))
   443  
   444  	AddConcepts([]string{path}, dictionary)
   445  
   446  	tokens, _ := parser.GenerateTokens(specText, "")
   447  	spec, parseResult := parser.CreateSpecification(tokens, dictionary, "")
   448  
   449  	c.Assert(parseResult.Ok, Equals, true)
   450  
   451  	firstStepInSpec := spec.Scenarios[0].Steps[0]
   452  	c.Assert(firstStepInSpec.IsConcept, Equals, true)
   453  	c.Assert(firstStepInSpec.GetArg("bar").ArgType, Equals, gauge.Dynamic)
   454  	c.Assert(firstStepInSpec.GetArg("far").ArgType, Equals, gauge.Dynamic)
   455  	c.Assert(firstStepInSpec.GetArg("bar").Value, Equals, "id")
   456  	c.Assert(firstStepInSpec.GetArg("far").Value, Equals, "name")
   457  
   458  	nestedConcept := firstStepInSpec.ConceptSteps[0]
   459  	c.Assert(nestedConcept.GetArg("baz").ArgType, Equals, gauge.Dynamic)
   460  	c.Assert(nestedConcept.GetArg("boo").ArgType, Equals, gauge.Dynamic)
   461  	c.Assert(nestedConcept.GetArg("baz").Value, Equals, "id")
   462  	c.Assert(nestedConcept.GetArg("boo").Value, Equals, "name")
   463  
   464  }
   465  
   466  func (s *MySuite) TestNestedConceptLooksUpWhenParameterPlaceholdersAreSame(c *C) {
   467  	parser := new(SpecParser)
   468  	specText := SpecBuilder().specHeading("A spec heading").
   469  		tableHeader("id", "name", "phone").
   470  		tableHeader("123", "prateek", "8800").
   471  		tableHeader("456", "apoorva", "9800").
   472  		tableHeader("789", "srikanth", "7900").
   473  		scenarioHeading("First scenario").
   474  		step("create user <id> <name> and <phone>").
   475  		step("another step").String()
   476  
   477  	dictionary := gauge.NewConceptDictionary()
   478  	path, _ := filepath.Abs(filepath.Join("testdata", "param_nested_concept2.cpt"))
   479  
   480  	AddConcepts([]string{path}, dictionary)
   481  
   482  	tokens, _ := parser.GenerateTokens(specText, "")
   483  	spec, parseResult := parser.CreateSpecification(tokens, dictionary, "")
   484  
   485  	c.Assert(parseResult.Ok, Equals, true)
   486  
   487  	firstStepInSpec := spec.Scenarios[0].Steps[0]
   488  	c.Assert(firstStepInSpec.IsConcept, Equals, true)
   489  	c.Assert(firstStepInSpec.GetArg("user-id").ArgType, Equals, gauge.Dynamic)
   490  	c.Assert(firstStepInSpec.GetArg("user-name").ArgType, Equals, gauge.Dynamic)
   491  	c.Assert(firstStepInSpec.GetArg("user-phone").ArgType, Equals, gauge.Dynamic)
   492  	c.Assert(firstStepInSpec.GetArg("user-id").Value, Equals, "id")
   493  	c.Assert(firstStepInSpec.GetArg("user-name").Value, Equals, "name")
   494  	c.Assert(firstStepInSpec.GetArg("user-phone").Value, Equals, "phone")
   495  
   496  	nestedConcept := firstStepInSpec.ConceptSteps[0]
   497  	c.Assert(nestedConcept.GetArg("user-id").ArgType, Equals, gauge.Dynamic)
   498  	c.Assert(nestedConcept.GetArg("user-name").ArgType, Equals, gauge.Dynamic)
   499  	c.Assert(nestedConcept.GetArg("user-id").Value, Equals, "id")
   500  	c.Assert(nestedConcept.GetArg("user-name").Value, Equals, "name")
   501  
   502  }
   503  
   504  func (s *MySuite) TestErrorOnCircularReferenceInConcept(c *C) {
   505  	cd := gauge.NewConceptDictionary()
   506  	cd.ConceptsMap["concept"] = &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept", Value: "concept", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: true}}}, FileName: "filename.cpt"}
   507  
   508  	res := ValidateConcepts(cd)
   509  
   510  	c.Assert(containsAny(res.ParseErrors, "Circular reference found"), Equals, true)
   511  }
   512  
   513  func (s *MySuite) TestValidateConceptShouldRemoveCircularConceptsFromDictionary(c *C) {
   514  	cd := gauge.NewConceptDictionary()
   515  	cd.ConceptsMap["concept"] = &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept", Value: "concept", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: true}}}, FileName: "filename.cpt"}
   516  	cd.ConceptsMap["concept2"] = &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept2", Value: "concept2", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: true}}}, FileName: "filename.cpt"}
   517  
   518  	res := ValidateConcepts(cd)
   519  
   520  	c.Assert(cd.ConceptsMap["concept"], Equals, (*gauge.Concept)(nil))
   521  	c.Assert(len(cd.ConceptsMap["concept2"].ConceptStep.ConceptSteps), Equals, 0)
   522  	c.Assert(len(res.ParseErrors), Equals, 1)
   523  	c.Assert(containsAny(res.ParseErrors, "Circular reference found"), Equals, true)
   524  }
   525  
   526  func (s *MySuite) TestRemoveAllReferences(c *C) {
   527  	cd := gauge.NewConceptDictionary()
   528  	cpt1 := &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept", Value: "concept", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: true}}}, FileName: "filename.cpt"}
   529  	cd.ConceptsMap["concept"] = cpt1
   530  	cd.ConceptsMap["concept2"] = &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept2", Value: "concept2", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: true}}}, FileName: "filename.cpt"}
   531  
   532  	c.Assert(len(cd.ConceptsMap["concept2"].ConceptStep.ConceptSteps), Equals, 1)
   533  
   534  	removeAllReferences(cd, cpt1)
   535  
   536  	c.Assert(len(cd.ConceptsMap["concept2"].ConceptStep.ConceptSteps), Equals, 0)
   537  }
   538  
   539  func (s *MySuite) TestReplaceNestedConceptsWithCircularReference(c *C) {
   540  	lookup := gauge.ArgLookup{}
   541  	lookup.AddArgName("a")
   542  	lookup.AddArgValue("a", &gauge.StepArg{Name: "", Value: "a", ArgType: gauge.Static})
   543  	lookup.ParamIndexMap = make(map[string]int)
   544  	lookup.ParamIndexMap["a"] = 0
   545  
   546  	cd := gauge.NewConceptDictionary()
   547  	path, _ := filepath.Abs(filepath.Join("testdata", "err", "cpt", "circular_concept.cpt"))
   548  
   549  	AddConcepts([]string{path}, cd)
   550  	concept := cd.Search("concept1 {}")
   551  
   552  	c.Assert(concept.ConceptStep.ConceptSteps[0].Lookup, DeepEquals, lookup)
   553  }
   554  
   555  func (s *MySuite) TestErrorParsingConceptWithRecursiveCallToConcept(c *C) {
   556  	cd := gauge.NewConceptDictionary()
   557  	cd.ConceptsMap["concept"] = &gauge.Concept{ConceptStep: &gauge.Step{LineText: "concept", Value: "concept", IsConcept: true, ConceptSteps: []*gauge.Step{&gauge.Step{LineText: "concept", Value: "concept", IsConcept: false}}}, FileName: "filename.cpt"}
   558  
   559  	res := ValidateConcepts(cd)
   560  
   561  	c.Assert(len(res.ParseErrors), Not(Equals), 0)
   562  	c.Assert(containsAny(res.ParseErrors, "Circular reference found"), Equals, true)
   563  }
   564  
   565  func (s *MySuite) TestConceptHavingDynamicParameters(c *C) {
   566  	conceptText := SpecBuilder().
   567  		specHeading("create user <user:id> <user:name> and <file>").
   568  		step("a step <user:id>").String()
   569  	step, _ := new(ConceptParser).Parse(conceptText, "")
   570  	c.Assert(step[0].LineText, Equals, "create user <user:id> <user:name> and <file>")
   571  	c.Assert(step[0].Args[0].ArgType, Equals, gauge.Dynamic)
   572  	c.Assert(step[0].Args[1].ArgType, Equals, gauge.Dynamic)
   573  	c.Assert(step[0].Args[2].ArgType, Equals, gauge.Dynamic)
   574  }
   575  
   576  func (s *MySuite) TestConceptHavingInvalidSpecialParameters(c *C) {
   577  	conceptText := SpecBuilder().
   578  		specHeading("create user <user:id> <table:name> and <file>").
   579  		step("a step <user:id>").String()
   580  	_, parseRes := new(ConceptParser).Parse(conceptText, "")
   581  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Dynamic parameter <table:name> could not be resolved")
   582  }
   583  
   584  func (s *MySuite) TestConceptHavingStaticParameters(c *C) {
   585  	conceptText := SpecBuilder().
   586  		specHeading("create user <user:id> \"abc\" and <file>").
   587  		step("a step <user:id>").String()
   588  	_, parseRes := new(ConceptParser).Parse(conceptText, "")
   589  	c.Assert(parseRes.ParseErrors[0].Message, Equals, "Concept heading can have only Dynamic Parameters")
   590  }
   591  
   592  func (s *MySuite) TestConceptFileHavingScenarioHeadingGivesParseError(c *C) {
   593  	conceptText := SpecBuilder().
   594  		specHeading("create user").
   595  		step("a step").
   596  		scenarioHeading("Scenario Heading").
   597  		step("a step1").
   598  		String()
   599  
   600  	scenarioHeading := SpecBuilder().
   601  		scenarioHeading("Scenario Heading").
   602  		String()
   603  	_, res := new(ConceptParser).Parse(conceptText, "")
   604  
   605  	c.Assert(len(res.ParseErrors), Not(Equals), 0)
   606  	c.Assert(res.ParseErrors[0].Message, Equals, "Scenario Heading is not allowed in concept file")
   607  	c.Assert(res.ParseErrors[0].LineText, Equals, strings.TrimSpace(scenarioHeading))
   608  }
   609  
   610  func (s *MySuite) TestConceptFileHavingStaticParamsInHeadingShouldGiveParseError(c *C) {
   611  	conceptText := SpecBuilder().
   612  		specHeading("Concept Heading37a").
   613  		step("a step").
   614  		specHeading("testinghjk \"sdf\"").
   615  		step("a step1").
   616  		String()
   617  
   618  	_, res := new(ConceptParser).Parse(conceptText, "")
   619  
   620  	c.Assert(len(res.ParseErrors), Not(Equals), 0)
   621  	c.Assert(res.ParseErrors[0].Message, Equals, "Concept heading can have only Dynamic Parameters")
   622  	c.Assert(res.ParseErrors[0].LineText, Equals, "testinghjk \"sdf\"")
   623  }
   624  
   625  func (s *MySuite) TestConceptFileHavingTableAfterConceptHeadingShouldGiveParseError(c *C) {
   626  	conceptText := SpecBuilder().
   627  		specHeading("Concept Heading37a").
   628  		step("a step").
   629  		specHeading("testinghjk ").
   630  		text("|sdfsdf|").
   631  		text("|----|").
   632  		text("|wer|").
   633  		step("a step1").
   634  		String()
   635  
   636  	_, res := new(ConceptParser).Parse(conceptText, "")
   637  
   638  	c.Assert(len(res.ParseErrors), Not(Equals), 0)
   639  	c.Assert(res.ParseErrors[0].Message, Equals, "Table doesn't belong to any step")
   640  	c.Assert(res.ParseErrors[0].LineText, Equals, "|sdfsdf|")
   641  }
   642  
   643  func (s *MySuite) TestMultipleConceptsInAFileHavingErrorsShouldBeConsolidated(c *C) {
   644  	conceptText := SpecBuilder().
   645  		specHeading("1<werwer>").
   646  		step("self <werwe1r>").
   647  		specHeading("2 <werwer> two").
   648  		step("self <werwer>").
   649  		String()
   650  
   651  	_, res := new(ConceptParser).Parse(conceptText, "")
   652  
   653  	c.Assert(len(res.ParseErrors), Not(Equals), 0)
   654  	c.Assert(res.ParseErrors[0].Message, Equals, "Dynamic parameter <werwe1r> could not be resolved")
   655  	c.Assert(res.ParseErrors[0].LineText, Equals, "self <werwe1r>")
   656  }
   657  
   658  func (s *MySuite) TestConceptFileHavingItemsWithDuplicateTableHeaders(c *C) {
   659  	conceptDictionary := gauge.NewConceptDictionary()
   660  	path, _ := filepath.Abs(filepath.Join("testdata", "tabular_concept1.cpt"))
   661  
   662  	AddConcepts([]string{path}, conceptDictionary)
   663  	concept := conceptDictionary.Search("my concept {}")
   664  	concept1 := conceptDictionary.Search("my {}")
   665  
   666  	c.Assert(concept, Not(Equals), nil)
   667  	c.Assert(concept1, Not(Equals), nil)
   668  }
   669  
   670  func (s *MySuite) TestConceptParserShouldNotAddTableAsArgIfCommentsArePresentBetweenStepAndTable(c *C) {
   671  	conceptText := SpecBuilder().
   672  		specHeading("create user").
   673  		step("a step").
   674  		text("adasdasd\n\n").
   675  		text("|sdfsdf|").
   676  		text("|----|").
   677  		text("|wer|").
   678  		step("a step1").
   679  		String()
   680  	steps, _ := new(ConceptParser).Parse(conceptText, "")
   681  	c.Assert(steps[0].ConceptSteps[0].GetLineText(), Equals, "a step")
   682  }
   683  
   684  func (s *MySuite) TestErrorParsingConceptWithNoSteps(c *C) {
   685  	parser := new(ConceptParser)
   686  	_, parseRes := parser.Parse("# my concept\n# second concept\n* first step ", "foo.cpt")
   687  	c.Assert(len(parseRes.ParseErrors), Equals, 1)
   688  	c.Assert(parseRes.ParseErrors[0].Error(), Equals, "foo.cpt:1 Concept should have atleast one step => 'my concept'")
   689  }
   690  
   691  func containsAny(errs []ParseError, msg string) bool {
   692  	for _, err := range errs {
   693  		if strings.Contains(err.Message, msg) {
   694  			return true
   695  		}
   696  	}
   697  	return false
   698  }