Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/completely.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

require 'completely/pattern'
require 'completely/completions'
require 'completely/tester'
2 changes: 2 additions & 0 deletions lib/completely/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'completely/commands/init'
require 'completely/commands/preview'
require 'completely/commands/generate'
require 'completely/commands/test'

module Completely
class CLI
Expand All @@ -13,6 +14,7 @@ def self.runner
runner.route 'init', to: Commands::Init
runner.route 'preview', to: Commands::Preview
runner.route 'generate', to: Commands::Generate
runner.route 'test', to: Commands::Test

runner
end
Expand Down
2 changes: 1 addition & 1 deletion lib/completely/commands/preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Preview < Base
usage "completely preview [CONFIG_PATH --function NAME]"
usage "completely preview (-h|--help)"

function_usage
function_usage
config_path_usage

def run
Expand Down
68 changes: 68 additions & 0 deletions lib/completely/commands/test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require 'completely/commands/base'

module Completely
module Commands
class Test < Base
summary "Test completions"

help <<~EOF
This command can be used to test that any completion script (either generated by compeltely or not) responds with the right completions.

In order to test on a completely configuration file other than 'completely.yaml', set the COMPLETELY_CONFIG_PATH environemnt variable.

In order to test on an arbitrary completions script, set the COMPLETELY_SCRIPT_PATH and optionally the COMPLETELY_SCRIPT_FUNCTION environment variables.
EOF

usage "completely test COMPLINE"
usage "completely test (-h|--help)"

param "COMPLINE", "The command to test completions for. This will be handled as if a TAB was pressed immediately at the end of it, so the last word is considered the active cursor. If you wish to complete for the next word instead, end your command with a space."

environment "COMPLETELY_CONFIG_PATH", "Path to a completely configuration file [default: completely.yaml]"
environment "COMPLETELY_SCRIPT_PATH", "Path to a completions script. When set, this script will be tested instead of the completely configuration file"
environment "COMPLETELY_SCRIPT_FUNCTION", "The main completion function to call when using a custom script. If not set, the basename of the script path will be used, prefixed by an underscore"

example %q[completely test "mygit pu"]
example %q[completely test "mygit pull "]
example <<~EOF
COMPLETELY_SCRIPT_PATH=/usr/share/bash-completion/completions/chown \\
completely test "chown --"
EOF

attr_reader :config, :script_path, :script_function

def run
set_vars
puts tester.test(compline).join "\n"
end

private

def compline
args['COMPLINE']
end

def tester
if config
completions = Completions.load config
completions.tester
else
Tester.new script_path: script_path, function_name: script_function
end
end

def set_vars
if ENV['COMPLETELY_CONFIG_PATH']
@config = ENV['COMPLETELY_CONFIG_PATH']
elsif ENV['COMPLETELY_SCRIPT_PATH']
@script_path = ENV['COMPLETELY_SCRIPT_PATH']
@script_function = ENV['COMPLETELY_SCRIPT_FUNCTION'] || "_#{File.basename(script_path)}"
elsif File.exist? 'completely.yaml'
@config = 'completely.yaml'
else
raise "Please set the proper environment variables or run in a folder with completely.yaml"
end
end
end
end
end
4 changes: 4 additions & 0 deletions lib/completely/completions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ def wrapper_function(name = nil)
"#{name}() {\n#{script_lines}\n}"
end

def tester
@tester ||= Tester.new script: script, function_name: function_name
end

private

def patterns!
Expand Down
13 changes: 13 additions & 0 deletions lib/completely/tester-template.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
<%= script || %Q[source "#{absolute_script_path}"] %>

# END OF COMPLETION SCRIPT

source /usr/share/bash-completion/bash_completion
COMP_WORDS=( <%= compline %> )
COMP_LINE="<%= compline %>"
COMP_POINT=${#COMP_LINE}
COMP_CWORD=<%= cword %>

<%= function_name %>
echo "${COMPREPLY[*]}"
48 changes: 48 additions & 0 deletions lib/completely/tester.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'erb'
require 'tempfile'

module Completely
class Tester
attr_reader :script, :script_path, :function_name, :cword, :compline

def initialize(script: nil, script_path: nil, function_name: )
@script, @script_path, @function_name = script, script_path, function_name
end

def test(compline)
Tempfile.create "completely-tester" do |f|
f << tester_script(compline)
f.flush
`bash #{f.path}`
end.split " "
end

def tester_script(compline)
set_compline_vars compline
ERB.new(template, trim_mode: '%-').result(binding)
end

protected

def set_compline_vars(compline)
@compline = compline
@cword = compline.split(' ').size - 1
@cword += 1 if compline.end_with? ' '
end

def absolute_script_path
@absolute_script_path ||= begin
script_path ? File.expand_path(script_path) : nil
end
end

def template_path
@template_path ||= File.expand_path "tester-template.erb", __dir__
end

def template
@template ||= File.read template_path
end

end
end
1 change: 1 addition & 0 deletions spec/approvals/cli/commands
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ Commands:
init Create a new sample YAML configuration file
preview Generate the bash completion script to STDOUT
generate Generate the bash completion script to a file
test Test completions

Run completely COMMAND --help for more information
2 changes: 2 additions & 0 deletions spec/approvals/cli/test/comps-apt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
update
upgrade
2 changes: 2 additions & 0 deletions spec/approvals/cli/test/comps-custom-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
command
conquer
2 changes: 2 additions & 0 deletions spec/approvals/cli/test/comps-default
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--help
--version
1 change: 1 addition & 0 deletions spec/approvals/cli/test/error
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#<RuntimeError: Please set the proper environment variables or run in a folder with completely.yaml>
44 changes: 44 additions & 0 deletions spec/approvals/cli/test/help
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Test completions

This command can be used to test that any completion script (either generated by
compeltely or not) responds with the right completions.

In order to test on a completely configuration file other than
'completely.yaml', set the COMPLETELY_CONFIG_PATH environemnt variable.

In order to test on an arbitrary completions script, set the
COMPLETELY_SCRIPT_PATH and optionally the COMPLETELY_SCRIPT_FUNCTION environment
variables.

Usage:
completely test COMPLINE
completely test (-h|--help)

Options:
-h --help
Show this help

Parameters:
COMPLINE
The command to test completions for. This will be handled as if a TAB was
pressed immediately at the end of it, so the last word is considered the
active cursor. If you wish to complete for the next word instead, end your
command with a space.

Environment Variables:
COMPLETELY_CONFIG_PATH
Path to a completely configuration file [default: completely.yaml]

COMPLETELY_SCRIPT_PATH
Path to a completions script. When set, this script will be tested instead
of the completely configuration file

COMPLETELY_SCRIPT_FUNCTION
The main completion function to call when using a custom script. If not set,
the basename of the script path will be used, prefixed by an underscore

Examples:
completely test "mygit pu"
completely test "mygit pull "
COMPLETELY_SCRIPT_PATH=/usr/share/bash-completion/completions/chown \
completely test "chown --"
3 changes: 3 additions & 0 deletions spec/approvals/cli/test/usage
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Usage:
completely test COMPLINE
completely test (-h|--help)
13 changes: 13 additions & 0 deletions spec/approvals/tester/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# some completion script

# END OF COMPLETION SCRIPT

source /usr/share/bash-completion/bash_completion
COMP_WORDS=( cli co )
COMP_LINE="cli co"
COMP_POINT=${#COMP_LINE}
COMP_CWORD=1

_cli_completions
echo "${COMPREPLY[*]}"
13 changes: 13 additions & 0 deletions spec/approvals/tester/script_path
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
source "<path removed>"

# END OF COMPLETION SCRIPT

source /usr/share/bash-completion/bash_completion
COMP_WORDS=( cli co )
COMP_LINE="cli co"
COMP_POINT=${#COMP_LINE}
COMP_CWORD=1

_cli_completions
echo "${COMPREPLY[*]}"
69 changes: 69 additions & 0 deletions spec/completely/commands/test_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require 'spec_helper'

describe Commands::Test do
subject { CLI.runner }

before do
system "cp lib/completely/sample.yaml completely.yaml"
ENV['COMPLETELY_CONFIG_PATH'] = nil
ENV['COMPLETELY_SCRIPT_PATH'] = nil
ENV['COMPLETELY_SCRIPT_FUNCTION'] = nil
end

after { system "rm -f completely.yaml" }

context "with --help" do
it "shows long usage" do
expect{ subject.run %w[test --help] }.to output_approval('cli/test/help')
end
end

context "without arguments" do
it "shows a short usage" do
expect { subject.run %w[test] }
.to output_approval('cli/test/usage')
end
end

context "with COMPLINE" do
it "prints completions" do
expect { subject.run ["test", "mygit --"] }
.to output_approval('cli/test/comps-default')
end
end

context "when COMPLETELY_CONFIG_PATH is set" do
before do
reset_tmp_dir
File.write "spec/tmp/in.yaml", { "play" => ["command", "conquer"] }.to_yaml
ENV['COMPLETELY_CONFIG_PATH'] = "spec/tmp/in.yaml"
end

it "tests against this completely file" do
expect { subject.run ["test", "play co"] }
.to output_approval('cli/test/comps-custom-config')
end
end

context "when COMPLETELY_SCRIPT_PATH and COMPLETELY_SCRIPT_FUNCTION are set" do
before do
ENV['COMPLETELY_SCRIPT_PATH'] = "/usr/share/bash-completion/completions/apt"
ENV['COMPLETELY_SCRIPT_FUNCTION'] = "_apt"
end

it "tests against this script" do
expect { subject.run ["test", "apt up"] }
.to output_approval('cli/test/comps-apt')
end
end

context "when there is no compeltely.yaml or any environment instructions" do
before { system "rm -f completely.yaml" }

it "fails gracefully" do
expect { subject.run ["test", "mygit --"] }
.to raise_approval('cli/test/error')
end
end

end
10 changes: 10 additions & 0 deletions spec/completely/completions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@
expect(subject.wrapper_function).to match_approval "completions/function"
end
end

describe '#tester', :focus do
it "returns a Tester object" do
expect(subject.tester).to be_a Tester
end

it "assigns self.script to tester.script" do
expect(subject.tester.script).to eq subject.script
end
end
end
38 changes: 38 additions & 0 deletions spec/completely/tester_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'spec_helper'

describe Tester do
subject { described_class.new script_path: script_path, function_name: function_name }
let(:function_name) { '_cli_completions' }
let(:script_path) { "spec/fixtures/tester/#{fixture}.bash" }
let(:fixture) { 'default' }
let(:compline) { "cli co" }

describe "#tester_script" do
it "sources the script using its absolute path" do
expect(subject.tester_script compline).to match %r[source "/.*spec/fixtures/tester/default.bash"]
end

it "returns a valid testing script" do
expect(subject.tester_script compline).to match_approval("tester/script_path")
.except(/source "(.*)"/, 'source "<path removed>"')
end
end

describe '#test' do
it "returns an array with completions" do
expect(subject.test compline).to eq ["command", "conquer"]
end
end

context "with script instead of script_path" do
subject { described_class.new script: script, function_name: function_name }
let(:script) { "# some completion script" }

describe '#tester_script' do
it "includes the embedded script" do
expect(subject.tester_script compline).to match_approval("tester/script")
end
end
end

end
Loading