Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cucumber-expressions: index 3 out of matches (IndexError) #329

Closed
nwallace opened this issue Jan 30, 2018 · 5 comments
Closed

cucumber-expressions: index 3 out of matches (IndexError) #329

nwallace opened this issue Jan 30, 2018 · 5 comments
Labels

Comments

@nwallace
Copy link

Summary

Given a certain (slightly complex) regexp to define a step definition, cucumber fails to load and I get an unfriendly error message "index 3 out of matches (IndexError)". The step definition looks like this:

Given /^I am a person( named "(?<first_name>.+) (?<last_name>.+)")?$/ do |first_name, last_name|
  ...
end

Expected Behavior

This step definition worked fine before (known to work against v2.4.0), so it should either work correctly or give me a helpful error message to help me fix the problem.

Current Behavior

An IndexError is raised when cucumber tries to load the step definitions.

$ cucumber
index 3 out of matches (IndexError)
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:20:in `offset'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:20:in `build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `block in build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `map'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `block in build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `map'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/group_builder.rb:19:in `build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/tree_regexp.rb:48:in `match'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/argument.rb:10:in `build'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-expressions-5.0.13/lib/cucumber/cucumber_expressions/regular_expression.rb:32:in `match'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/glue/step_definition.rb:101:in `arguments_from'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/glue/registry_and_more.rb:66:in `block in step_matches'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/glue/registry_and_more.rb:65:in `each'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/glue/registry_and_more.rb:65:in `reduce'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/glue/registry_and_more.rb:65:in `step_matches'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/step_match_search.rb:19:in `call'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/step_match_search.rb:19:in `call'
/home/nathan/.rubies/ruby-2.5.0/lib/ruby/2.5.0/delegate.rb:83:in `method_missing'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/step_match_search.rb:62:in `call'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:66:in `matches'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:47:in `result'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:37:in `find_match'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:33:in `attempt_to_activate'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:29:in `map'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:29:in `new_test_steps'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:23:in `test_case'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/filters/activate_steps.rb:12:in `test_case'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/test/case.rb:25:in `describe_to'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/test/filters/locations_filter.rb:18:in `block in done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/test/filters/locations_filter.rb:17:in `each'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/test/filters/locations_filter.rb:17:in `done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/filter.rb:62:in `done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/test/filters/tag_filter.rb:18:in `done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/compiler.rb:24:in `done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core/gherkin/parser.rb:37:in `done'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core.rb:32:in `parse'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-core-3.1.0/lib/cucumber/core.rb:21:in `compile'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/runtime.rb:74:in `run!'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/lib/cucumber/cli/main.rb:33:in `execute!'
/home/nathan/.gem/ruby/2.5.0/gems/cucumber-3.1.0/bin/cucumber:9:in `<top (required)>'
/home/nathan/.gem/ruby/2.5.0/bin/cucumber:23:in `load'
/home/nathan/.gem/ruby/2.5.0/bin/cucumber:23:in `<top (required)>'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:75:in `load'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:75:in `kernel_load'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli/exec.rb:28:in `run'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli.rb:424:in `exec'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor.rb:387:in `dispatch'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli.rb:27:in `dispatch'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/vendor/thor/lib/thor/base.rb:466:in `start'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/cli.rb:18:in `start'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/exe/bundle:30:in `block in <top (required)>'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/lib/bundler/friendly_errors.rb:122:in `with_friendly_errors'
/home/nathan/.gem/ruby/2.5.0/gems/bundler-1.16.1/exe/bundle:22:in `<top (required)>'
/home/nathan/.gem/ruby/2.5.0/bin/bundle:23:in `load'
/home/nathan/.gem/ruby/2.5.0/bin/bundle:23:in `<main>'

Steps to Reproduce (for bugs)

Minimal demo of behavior here: https://github.com/nwallace/cucumber-index-error-bug
Clone the repo, install ruby 2.5.0 (if necessary), bundle install, cucumber

Your Environment

  • Version used: 3.1.0
  • Operating System and version: Arch Linux
@nwallace
Copy link
Author

It appears to be caused by the named captures inside the optional group. Without the names, I get a nice error message:

Given /^I am a person( named "(.+) (.+)")?$/ do |first_name, last_name|
  ...
end
$ cucumber
Feature: Demonstrate IndexError bug

  Scenario: It cannot handle this Regexp       # features/index_error.feature:3
    Given I am a person named "Charlotte Rose" # features/step_definitions/error_steps.rb:1
      Single transformer unexpectedly matched 2 values - "Charlotte" and "Rose" (Cucumber::CucumberExpressions::CucumberExpressionError)
      features/index_error.feature:4:in `Given I am a person named "Charlotte Rose"'
    Then my first name is "Charlotte"          # features/step_definitions/error_steps.rb:6
    And my last name is "Rose"                 # features/step_definitions/error_steps.rb:10

Failing Scenarios:
cucumber features/index_error.feature:3 # Scenario: It cannot handle this Regexp

@aslakhellesoy
Copy link
Contributor

Hi @nwallace adding support for named capture groups should be easy to do, I'll handle that. When that's fixed, you'll get the same error message as when you use (.*).

Out of curiosity, why did you wrap thefirst_name and last_name capture groups in a surrounding one?

@nwallace
Copy link
Author

Sometimes I want to specify the person's name and sometimes I don't care what their name is. I was surprised when it worked the way I wanted back on the old version, but it's understandable that that would be hard to parse by cucumber. It's easy enough to just have two separate step definitions 👍

@aslakhellesoy
Copy link
Contributor

aslakhellesoy commented Jan 31, 2018

I've tracked this down to what seems to be a bug in Ruby's RegExp. It turns out a RegExp with a mix of unnamed and named capture groups only exposes access to the named capture groups, and not the unnamed ones.

m = /(a)(?<x>b)/.match('ab')
m.length # => 2
m[0] # => 'ab'
m[1] # => 'b'
m[:x] # => 'b'

There is no way to access the capture group containing the a.

Because of this bug I think our best option is to simply disallow named capture groups in Cucumber.

WDYT?

@lock
Copy link

lock bot commented Jan 31, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants