rubytddcucumberaruba

How to get Aruba to expand wildcards


I'm writing a simple command line gem.

The library that does the actual work was developed with rspec and so far that works.

I'm trying to test the command line portion with Aruba/Cucumber, but I've come across some strange behaviour.

Just to test this, I've got a the binary file to puts ARGV, and I've got test files in tmp/aruba

When I run bundle exec gem_name tmp/aruba/*.* I am presented with the list of shell expanded file names.

Now my features file has:

Given files to work on       # I set up files in tmp/aruba in this step
When I run `gem_name *.*`    # standard step
Then the output should contain "Wibble"

The last step is obviously going to fail, but it shows me a diff between what it expects and the actual output. Rather than seeing a list of shell expanded filenames, all I get is "*.*"

So I'm left in the position of having an app that actually works as expected, but I can't get the tests to pass. I could take the "." and generate the list of files from there, but then I'm writing extra production code just to get the app to work under test - which I don't think is the correct way to go about it. And all because shell expansion isn't happening.

If you look at my profile, you'll see that Ruby isn't my main bag, feel free to point me at any resources that I may have missed about this, but is this just me missing something, or expected behaviour that somebody knows how to work around?


Solution

  • After a little digging in the Aruba source I figured out that the When I run step ends up in a code block like this:

    def run!(&block)
      @process = ChildProcess.build(*shellwords(@cmd))
      ...
      begin
        @process.start
        ...
    

    Further digging into ChildProcess ends up here:

    def launch_process
      ...
      begin
        exec(*@args)
        ...
    

    And therein lies the problem. exec does not do shell expansion when the argument list is split into multiple array elements:

    If exec is given a single argument, that argument is taken as a line that is subject to shell expansion before being executed. If multiple arguments are given, the second and subsequent arguments are passed as parameters to command with no shell expansion.

    However playing with shellwords a bit we find:

    Shellwords.shellwords('gem_name *.*')
    => ["gem_name", "*.*"]                   # No good
    Shellwords.shellwords('"gem_name *.*"')
    => ["gem_name *.*"]                      # Aha!
    

    Therefore the solution might be as simple as:

    When I run `"gem_name *.*"`
    

    If that doesn't work then you are pretty much out of luck. I would suggest you expand the file names manually since you're not really testing shell expansion here - we know that works: you are testing multiple arguments.

    Therefore you should instead do:

    When I run `gem_name your_file1 your_file2 your_file3`