Skip to content

Commit

Permalink
fixes step tables which are not last steps; fixes clear of step table…
Browse files Browse the repository at this point in the history
… for multiple uses of step
  • Loading branch information
shaunc committed May 3, 2016
1 parent 96705b2 commit 0ef999b
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 27 deletions.
4 changes: 1 addition & 3 deletions cucumber/feature.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 10 additions & 6 deletions cucumber/parameter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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*(
Expand Down Expand Up @@ -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))
```
]##
Expand Down
6 changes: 5 additions & 1 deletion cucumber/runner.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
14 changes: 7 additions & 7 deletions cucumber/step.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]

Expand Down
21 changes: 13 additions & 8 deletions readme.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.


Expand All @@ -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.

Expand Down
21 changes: 20 additions & 1 deletion tests/features/parse_gherkin.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand All @@ -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 "<foo1>"
Examples:
| foo1 |
| 1 |
"""
Then step 0 of scenario 0 has table with 1 row and columns:
| name |
| bar |

2 changes: 1 addition & 1 deletion tests/steps/featureSteps.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 <istep> of scenario <iscenario> has table with <irows> rows and columns:", (
Then r"step <istep> of scenario <iscenario> has table with <irows> rows? and columns:", (
scenario.feature: Feature,
istep: int, iscenario: int, irows: int, column.name: seq[string]):
let step = feature.scenarios[iscenario].steps[istep]
Expand Down

0 comments on commit 0ef999b

Please sign in to comment.