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