diff --git a/cucumber/feature.nim b/cucumber/feature.nim index ff4063b..9693e09 100644 --- a/cucumber/feature.nim +++ b/cucumber/feature.nim @@ -390,11 +390,9 @@ proc readExamples( step.table = result while true: let line = stream.nextLine - if line.ltype != ltBody: + if line.ltype != ltBody or line.content.match(re"\|.*\|$").isNone: stream.pushback line break - if line.content.match(re("|.*|$")).isNone: - raise newSyntaxError(line, "Malformed examples table.") let row = line.content.split('|')[1..^2].mapIt it.strip() if result.columns.len == 0: result.columns.add row diff --git a/cucumber/parameter.nim b/cucumber/parameter.nim index cd5eeec..3c0c72f 100644 --- a/cucumber/parameter.nim +++ b/cucumber/parameter.nim @@ -148,16 +148,19 @@ macro declareContextColumnSetter( let subt = name[4..^2] let setterName = pubName(nil, ptName(name, "ColumnSetter")) let varName = newIdentNode("varName") - let strVal = newIdentNode("strVal") + let strValues = newIdentNode("strValues") let contextExpr = newCall( ptName(name, "Getter"), newIdentNode("ctTable"), varName) let parseFctName = ptName(subt, "parseFct") - let callParse = newCall(parseFctName, strVal) - let addStmt = newCall(newDot(contextExpr, "add"), callParse) + let idx = newIdentNode("idx") + let val = newIdentNode("val") + let callParse = newCall(parseFctName, val) result = quote do: proc `setterName`( - `varName`: string, `strVal`: string): void = - `addStmt` + `varName`: string, `strValues`: seq[string]): void = + setLen(`contextExpr`, `strValues`.len) + for `idx`, `val` in `strValues`: + `contextExpr`[`idx`] = `callParse` #echo result.toStrLit.strVal template DeclareParamType*( @@ -201,7 +204,8 @@ template DeclareParamType*( defined as above (mutatis mutandis), but with the addition of: ```nim - proc paramTypeSeqIntColumnSetter(varName: string, strVal: string): void = + proc paramTypeSeqIntColumnSetter(varName: string, strValues: seq[string]): void = + paramTypeSeqIntContext(ctTable, varName).add(parseInt(strVal)) ``` ]## diff --git a/cucumber/runner.nim b/cucumber/runner.nim index 184a93f..66d0811 100644 --- a/cucumber/runner.nim +++ b/cucumber/runner.nim @@ -350,8 +350,12 @@ proc fillTable(sd: StepDefinition, stepTable: Examples): void = return for icol, colName in stepTable.columns: let setter = sd.columns[colName] + var col = newSeq[string]() for row in stepTable.values: - setter(row[icol]) + col.add(row[icol]) + setter(col) + # for row in stepTable.values: + # setter(row[icol]) when isMainModule: diff --git a/cucumber/step.nim b/cucumber/step.nim index e81d8dd..e628115 100644 --- a/cucumber/step.nim +++ b/cucumber/step.nim @@ -17,7 +17,7 @@ export types.StepArgs export parameter.resetContext type - ColumnSetter* = proc(sval: string): void + ColumnSetter* = proc(svalues: seq[string]): void StepDefinitionObj* = object stepType*: StepType @@ -105,8 +105,8 @@ proc step( let stepDef = StepDefinition( stepRE: stepRE, defn: stepDefinition, blockParamName: "c" columns: newTable[string, ColumnSetter]()) - stepDef.columns["d"] = proc(strVal: string): void = - paramTypeSeqIntColumnSetter("d", strVal) + stepDef.columns["d"] = proc(strValues: seq[string]): void = + paramTypeSeqIntColumnSetter("d", strValues) stepDefinitions[stGiven].add(stepDef) Argument list syntax: @@ -218,7 +218,7 @@ proc unpackArg*(argdef: NimNode) : ArgSpec = aname = $anameN if atypeN.kind == nnkVarTy: avar = true - atype = $atypeN[0] + atype = $(atypeN[0]) else: atype = atypeN.toStrLit.strVal return (aname, atype, aloc, avar) @@ -261,10 +261,10 @@ proc subsPattern( proc newColumnInit(aname: string, atype: string, stepDef: NimNode): NimNode = let csetter = ptName(atype, "columnSetter") let colTarget = newBrkt(newDot(stepDef, "columns"), aname.newLit) - let strVal = newIdentNode("strVal") - let csetStmt = newCall(csetter, aname.newLit, strVal) + let strValues = newIdentNode("strValues") + let csetStmt = newCall(csetter, aname.newLit, strValues) let slist = quote do: - `colTarget` = proc(`strVal`: string): void = + `colTarget` = proc(`strValues`: seq[string]): void = `csetStmt` result = slist[0] diff --git a/readme.rst b/readme.rst index 914abc0..3187ce9 100644 --- a/readme.rst +++ b/readme.rst @@ -197,9 +197,9 @@ Parameter Types ~~~~~~~~~~~~~~~ The type of a formal parameter is a "parameter type" -- which doesn't -(necessarily) correspond to a nim type. The "cucumber/parameters" defines -some common types (currently: int, string, bool. TODO: add float at least). -It also defines the ``DeclareParamType`` and ``DeclareRefParamType`` +(necessarily) correspond to a nim type. The "cucumber/parameters" defines some +common types (currently: int, string, bool and float, as well as sequences of +these). It also defines the ``DeclareParamType`` and ``DeclareRefParamType`` macros, which can be used to define other parameter types. @@ -214,14 +214,19 @@ Where: * ``name``: Name of the parameter type (to be used in argument list specification). -* ``ptype``: actual nim type (not quoted). Is used to declare variables +* ``ptype``: Actual nim type (not quoted). Is used to declare variables in step definitions. -* ``parseFct``: fuction which takes a string and returns parsed value - of type ``ptype``. Can be ``nil`` for arguments not from step text (e.g. +* ``parseFct``: Function which takes a string and returns parsed value + of type ``ptype``. + + Can be ``nil`` for arguments not from step text (e.g. which are just stored in context). -* ``newFct``: function which can be used to initialize or create a value - of type ``ptype``. If ``nil`` then ``nil`` will be used as initial value. +* ``newFct``: Function which can be used to initialize or create a value + of type ``ptype``. + + If ``nil`` then ``nil`` will be used as initial value. (This is only legal if it is legal for ``ptype``). + * ``pattern``: string pattern which can be used as default capture in regex. Can be nil; if defined must define exactly one capture group. diff --git a/tests/features/parse_gherkin.feature b/tests/features/parse_gherkin.feature index 0cef8ae..d00fb2b 100644 --- a/tests/features/parse_gherkin.feature +++ b/tests/features/parse_gherkin.feature @@ -383,7 +383,6 @@ Scenario: Feature and scenarios may all have multiple tags # tables in steps -@check Scenario: A step may define a table When I read the feature file: """ @@ -399,3 +398,23 @@ Scenario: A step may define a table | name | | a | | b | + +Scenario: A scenario may have both step table and examples. + When I read the feature file: + """ + Feature: parse gherkin + + Scenario: step table and examples + Given table: + | bar | + | baz | + Given "" + + Examples: + | foo1 | + | 1 | + """ + Then step 0 of scenario 0 has table with 1 row and columns: + | name | + | bar | + diff --git a/tests/steps/featureSteps.nim b/tests/steps/featureSteps.nim index 2ea86b4..172d373 100644 --- a/tests/steps/featureSteps.nim +++ b/tests/steps/featureSteps.nim @@ -137,7 +137,7 @@ Then r"""column (\d+) of example (\d+), scenario (\d+) is named \"([^\"]*)\"""", let column = example.columns[icolumn] assert column == columnName -Then r"step of scenario has table with rows and columns:", ( +Then r"step of scenario has table with rows? and columns:", ( scenario.feature: Feature, istep: int, iscenario: int, irows: int, column.name: seq[string]): let step = feature.scenarios[iscenario].steps[istep]