Skip to content

Commit

Permalink
Interpolate other variables in values (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop authored Jul 4, 2022
1 parent 02ea3ed commit 9c58e49
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 19 deletions.
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,25 @@ Feature: Variables
# Set values to multiple variables.
# Values are decoded into `any` with JSON decoder.
# Beware that both integers and floats will be decoded as `float64`.
# String values can interpolate other variables (see $replaced).
When variables are set to values
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $replaced | "$qux/test/$bar" |
# Assert current values of multiple variables.
# String values can interpolate other variables (see $replaced: "$qux/test/$bar").
Then variables are equal to values
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $replaced | "123/test/abc" |
| $replaced | "$qux/test/$bar" |
And variable $qux equals to 123
And variable $replaced equals to "$qux/test/$bar"
And variable $replaced equals to "123/test/abc"
```

Libraries can pass variables using context.
Expand Down
23 changes: 15 additions & 8 deletions _testdata/Vars.feature
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ Feature: Variables
# Set values to multiple variables.
# Values are decoded into `any` with JSON decoder.
# Beware that both integers and floats will be decoded as `float64`.
# String values can interpolate other variables (see $replaced).
When variables are set to values
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $replaced | "$qux/test/$bar" |
# Assert current values of multiple variables.
# String values can interpolate other variables (see $replaced: "$qux/test/$bar").
Then variables are equal to values
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $bar | "abc" |
| $baz | {"one":1,"two":2} |
| $qux | 123 |
| $quux | true |
| $replaced | "123/test/abc" |
| $replaced | "$qux/test/$bar" |
And variable $qux equals to 123
And variable $replaced equals to "$qux/test/$bar"
And variable $replaced equals to "123/test/abc"


# Use vars in custom steps.
Expand Down
65 changes: 62 additions & 3 deletions steps.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package vars

import (
"bytes"
"context"
"encoding/json"
"fmt"
"sort"
"strings"

"github.com/bool64/shared"
"github.com/cucumber/godog"
Expand Down Expand Up @@ -75,12 +78,18 @@ func (s *Steps) varIsUndefined(ctx context.Context, name string) error {
}

func (s *Steps) varIsSet(ctx context.Context, name, value string) (context.Context, error) {
ctx, v := s.JSONComparer.Vars.Fork(ctx)

rv, err := replaceString(value, v)
if err != nil {
return ctx, fmt.Errorf("failed to replace vars in %s: %w", value, err)
}

var val interface{}
if err := json.Unmarshal([]byte(value), &val); err != nil {
if err := json.Unmarshal([]byte(rv), &val); err != nil {
return ctx, fmt.Errorf("failed to decode variable %s with value %s as JSON: %w", name, value, err)
}

ctx, v := s.JSONComparer.Vars.Fork(ctx)
v.Set(s.varPrefix+name, val)

return ctx, nil
Expand All @@ -89,12 +98,17 @@ func (s *Steps) varIsSet(ctx context.Context, name, value string) (context.Conte
func (s *Steps) varEquals(ctx context.Context, name, value string) error {
_, v := s.JSONComparer.Vars.Fork(ctx)

rv, err := replaceString(value, v)
if err != nil {
return fmt.Errorf("failed to replace vars in %s: %w", value, err)
}

stored, found := v.Get(s.varPrefix + name)
if !found {
return fmt.Errorf("could not find variable %s", name)
}

if err := assertjson.FailNotEqualMarshal([]byte(value), stored); err != nil {
if err := assertjson.FailNotEqualMarshal([]byte(rv), stored); err != nil {
return fmt.Errorf("variable %s assertion failed: %w", name, err)
}

Expand All @@ -112,6 +126,11 @@ func (s *Steps) varsAreSet(ctx context.Context, table *godog.Table) (context.Con
name := row.Cells[0].Value
value := row.Cells[1].Value

value, err := replaceString(value, v)
if err != nil {
return ctx, fmt.Errorf("failed to replace vars in %s: %w", row.Cells[1].Value, err)
}

var val interface{}
if err := json.Unmarshal([]byte(value), &val); err != nil {
return ctx, fmt.Errorf("failed to decode variable %s with value %s as JSON: %w", name, value, err)
Expand All @@ -134,6 +153,11 @@ func (s *Steps) varsAreEqual(ctx context.Context, table *godog.Table) error {
name := row.Cells[0].Value
value := row.Cells[1].Value

value, err := replaceString(value, v)
if err != nil {
return fmt.Errorf("failed to replace vars in %s: %w", row.Cells[1].Value, err)
}

stored, found := v.Get(name)
if !found {
return fmt.Errorf("could not find variable %s", name)
Expand All @@ -146,3 +170,38 @@ func (s *Steps) varsAreEqual(ctx context.Context, table *godog.Table) error {

return nil
}

func replaceString(s string, vars *shared.Vars) (string, error) {
if vars != nil {
type kv struct {
k string
v string
}

vv := vars.GetAll()
kvs := make([]kv, 0, len(vv))

for k, v := range vv {
vs, err := json.Marshal(v)
if err != nil {
return "", fmt.Errorf("failed to marshal var %s (%v): %w", k, v, err)
}

if vs[0] == '"' {
vs = bytes.Trim(vs, `"`)
}

kvs = append(kvs, kv{k: k, v: string(vs)})
}

sort.Slice(kvs, func(i, j int) bool {
return len(kvs[i].k) > len(kvs[j].k)
})

for _, kv := range kvs {
s = strings.ReplaceAll(s, kv.k, kv.v)
}
}

return s, nil
}

0 comments on commit 9c58e49

Please sign in to comment.