From 63fd25dacbe6ebee2a1b39aee123edf7162a2cca Mon Sep 17 00:00:00 2001 From: Jorge Bucaran Date: Tue, 13 Jan 2015 20:30:24 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9D=AF=E2=9D=AF=E2=9D=AF=20Complete=20overha?= =?UTF-8?q?ul=20of=20brand=20new=20Oh-My-Fish=20test=20framework.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Add documentation and examples. + Add new functions to interact with the framework: + spec.eval - eval a function by name and echo its description field + spec.functions - prints functions currently in scope that match the key glob + spec.log - log a message / test result + spec.run - run suite of tests + Rename list.erase to erase. --- plugins/fish-spec/expect.fish | 76 +++++++++------- plugins/fish-spec/fish-spec.load | 1 - plugins/fish-spec/function.fish | 0 plugins/fish-spec/list.erase.fish | 5 +- plugins/fish-spec/run_spec.fish | 13 --- plugins/fish-spec/run_specs.fish | 17 ---- plugins/fish-spec/spec.eval.fish | 96 +++++++++++++++++++++ plugins/fish-spec/spec.functions.fish | 16 ++++ plugins/fish-spec/spec.log.fish | 56 ++++++++++++ plugins/fish-spec/spec.run.fish | 65 ++++++++++++++ plugins/fish-spec/spec/list.erase.spec.fish | 56 ++++++++++++ plugins/fish-spec/test/list.erase.test.fish | 48 ----------- spec/oh-my-fish.spec.fish | 79 +++++++++++++++++ test/oh_my_fish.test.fish | 73 ---------------- 14 files changed, 415 insertions(+), 186 deletions(-) delete mode 100644 plugins/fish-spec/fish-spec.load delete mode 100644 plugins/fish-spec/function.fish delete mode 100644 plugins/fish-spec/run_spec.fish delete mode 100644 plugins/fish-spec/run_specs.fish create mode 100644 plugins/fish-spec/spec.eval.fish create mode 100644 plugins/fish-spec/spec.functions.fish create mode 100644 plugins/fish-spec/spec.log.fish create mode 100644 plugins/fish-spec/spec.run.fish create mode 100644 plugins/fish-spec/spec/list.erase.spec.fish delete mode 100644 plugins/fish-spec/test/list.erase.test.fish create mode 100755 spec/oh-my-fish.spec.fish delete mode 100644 test/oh_my_fish.test.fish diff --git a/plugins/fish-spec/expect.fish b/plugins/fish-spec/expect.fish index 1b2df9d..5931491 100644 --- a/plugins/fish-spec/expect.fish +++ b/plugins/fish-spec/expect.fish @@ -1,34 +1,48 @@ +# NAME +# expect - assert a list of expected values match an actual value. +# +# SYNOPSIS +# expect ... +# +# --to-equal value equals value +# --to-contain value exists in list +# --to-no-contain value does not exist in list +# +# +# EXAMPLE +# import plugins/fish-spec +# +# function describe_my_test +# function it_does_my_task +# set -l result (my_task $data) +# expect $result --to-equal 0 +# end +# end +# spec.run +#/ function expect - set -l expected $argv[1..-3] - set -l comparison $argv[-2] - set -l actual $argv[-1] - - switch $comparison - case 'to_equal' - if test "$expected" = "$actual" - emit assertion_success - else - emit assertion_failure "Expected: \"$expected\""\n" Actual: \"$actual\"" - end - - case 'to_include' - set -l item $actual - set -l list $expected - - if contains -- "$item" $list - emit assertion_success - else - emit assertion_failure "Expected \"$list\" to include \"$item\"" - end - - case 'to_not_include' - set -l item $actual - set -l list $expected - - if not contains -- "$item" $list - emit assertion_success - else - emit assertion_failure "Expected \"$list\" to not include \"$item\"" - end + set -l expected $argv[1..-3] + set -l condition $argv[-2] + set -l actual $argv[-1] + set -l result 0 + # Test conditions and save success/fail $status to return later. + switch $condition + case --to-eq\* + test "$expected" = "$actual" + case --to-contain + set actual_text "To contain" + contains -- "$actual" $expected + case --to-not-contain + set actual_text "To not contain" + not contains -- "$actual" $expected end + set result $status + if [ $result -eq 0 ] + spec.log --ok + else + spec.log --fail red \n"Expected" yellow "$expected" \ + red \n(echo $condition | tr "-" " " \ + | cut -c 3-) yellow "$actual" + end + return $result end diff --git a/plugins/fish-spec/fish-spec.load b/plugins/fish-spec/fish-spec.load deleted file mode 100644 index b7b6102..0000000 --- a/plugins/fish-spec/fish-spec.load +++ /dev/null @@ -1 +0,0 @@ -run_specs diff --git a/plugins/fish-spec/function.fish b/plugins/fish-spec/function.fish deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/fish-spec/list.erase.fish b/plugins/fish-spec/list.erase.fish index d574151..870f093 100644 --- a/plugins/fish-spec/list.erase.fish +++ b/plugins/fish-spec/list.erase.fish @@ -1,5 +1,5 @@ # NAME -# list.erase - erase items from lists +# list.erase - erase any items from one or more lists # # SYNOPSIS # [...] [--from] @@ -13,10 +13,9 @@ # While items are basically any valid sequence of symbols, lists refer # to any global variable or local variable in the scope of the calling # function by name. -# #/ function -S list.erase - # List to erase from is last item by default. + # List to erase from is at last index by default. set -l items $argv[1..-2] set -l lists $argv[-1] if set -l index (contains -i -- --from $argv) diff --git a/plugins/fish-spec/run_spec.fish b/plugins/fish-spec/run_spec.fish deleted file mode 100644 index 64bcc69..0000000 --- a/plugins/fish-spec/run_spec.fish +++ /dev/null @@ -1,13 +0,0 @@ -function run_spec -a test - functions -q before_each; and before_each - eval $test - functions -q after_each; and after_each -end - -function run_spec._.results.assertion_success -e assertion_success - printf '.' -end - -function run_spec._.results.assertion_failure -e assertion_failure - echo $argv -end diff --git a/plugins/fish-spec/run_specs.fish b/plugins/fish-spec/run_specs.fish deleted file mode 100644 index f826543..0000000 --- a/plugins/fish-spec/run_specs.fish +++ /dev/null @@ -1,17 +0,0 @@ -function run_specs - # Run each describe function - for describe in (functions -n | grep describe_) - eval $describe - end - - # Run before all block - functions -q before_all; and before_all - - # Run tests - for test in (functions -n | grep it_) - run_spec $test - end - - # Run after all block - functions -q after_all; and after_all -end diff --git a/plugins/fish-spec/spec.eval.fish b/plugins/fish-spec/spec.eval.fish new file mode 100644 index 0000000..246b127 --- /dev/null +++ b/plugins/fish-spec/spec.eval.fish @@ -0,0 +1,96 @@ +# NAME +# spec.eval - eval a function by name and echo its description field +# +# SYNOPSIS +# spec.eval [OPTIONS...] + +# OPTIONS +# +# Name / glob of one or more functions to evaluate. By default find all +# functions that match the glob and test each. To run a single function, +# use the -u --unit option as described below. +# +# [-u --unit] +# Evaluate a single function as indicated by . +# +# [-d --depth ] +# Used to calculate the increment rate of padding added to test blocks. +# A depth of N will prepend N*2 spaces to test descriptions. No padding +# is added by default. Use a depth of 0 to NOT output newlines between +# each test log output. +# +# [-s --silent] +# Do NOT output test descriptions. This option is off by default. +# +# DESCRIPTION +# Run the specified function. Add a -d --description field to tests in +# order to log a message before evaluating the function. Use the depth +# option to indicate the indentation factor when logging a message. +# +# The process is split up in these steps: +# +# 1. Extract test name. +# 2. Parse description from function definition if available. +# 3. Parse options +# + Calculate indentation from --depth * $tab. +# + Determine newline output. +# + Skip output if -s --silent is specified. +# +# EXAMPLES +# spec.eval "describe_" --depth 0 +# spec.eval "teardown_" +# spec.eval "it_" +# spec.eval "my_test" --unit +#/ +function spec.eval -d "Eval a function by name and echo its description field." + # Parse and print description field of a function. + # spec.get.info + function spec.get.info -a name + type $name \ + | head -n 2 \ + | tail -n 1 \ + | cut -d" " -f4- \ + | sed "s/^\'//g" \ + | sed "s/\'\$//g" + end + + set -l default_color white + # Keep a copy in case -u --unit option is used. + set -l query $argv[1] + # Collect all functions that start with $query's key. + set -l tests (spec.functions $query) + set -l tab 2 + set -l indent "" + set -l newline \n + set -l silent "" + + for index in (seq (count $argv)) + switch $argv[$index] + case -d --depth + set -l depth $argv[(math $index + 1)] + if [ $depth -gt 0 ] + set indent (printf " %.0s" (seq (math $depth \* $tab))) + else + set newline "" + end + case -s --silent + set silent $argv[$index] + case -u --unit + # Evaluate query as a single function instead of a set. + set tests $query + end + end + + for test in $tests + if [ -z "$silent" ] + set -l info (spec.get.info $tests) + if [ -n "$info" ] + # Do not print empty lines for tests with empty descriptions. + set info $newline$indent$info + end + spec.log --message $default_color "$info" + end + eval $test + or return 1 + end +end diff --git a/plugins/fish-spec/spec.functions.fish b/plugins/fish-spec/spec.functions.fish new file mode 100644 index 0000000..eecab75 --- /dev/null +++ b/plugins/fish-spec/spec.functions.fish @@ -0,0 +1,16 @@ +# NAME +# spec.functions - echo functions existing in the global scope that match +# the key glob. +# SYNOPSIS +# spec.functions +# +# EXAMPLES +# spec.functions "describe_" +# spec.functions "before_" +#/ +function spec.functions -a key + if [ -n "$key" ] + # Skip empty strings to avoid fetching all global functions. + functions -n | grep \^"$key" + end +end diff --git a/plugins/fish-spec/spec.log.fish b/plugins/fish-spec/spec.log.fish new file mode 100644 index 0000000..4535614 --- /dev/null +++ b/plugins/fish-spec/spec.log.fish @@ -0,0 +1,56 @@ +# NAME +# spec.log - log a message / test result +# +# SYNOPSIS +# spec.log -m | --msg/--message +# -o | --ok +# -f | --fail +# [ ...] +# OPTIONS +# -m --msg --message +# Output the message according to the ... list. +# +# -o --ok +# Echo a . character. Optionally, print a list of ... +# messages. +# +# -f --fail +# Echo a ✘ character. Optionally, print a list of ... +# messages. Use this feature to indicate the expected value, condition +# description and actual value of the failed assertion. For example: +# +# spec.log --fail red "Expected" blue "$value" +# +# NOTES +# This function does not modify the $status variable. +# +# Some tests may specify multiple success conditions, invoking `expect` +# several times per test case. In this case, spec.log will be run once +# each per `expect` call. +# +# Notice that a message in the form [ ...] implies that +# colors occupy odd and strings even indices after the first option. +#/ +function spec.log -d "Log / commit a message or test result." + switch $argv[1] + case -o --ok + set -e argv[1] + set argv green . $argv + case -f --fail + set -e argv[1] + set argv red ✘ $argv + case -m --msg --message + # Default message color. + set -e argv[1] + end + + if [ (count $argv) -gt 0 ] + for i in (seq (count $argv)) + if [ (math "$i % 2") -eq 0 ] + echo -ne $argv[$i](set_color white) + else + set_color $argv[$i] + end + end + end +end diff --git a/plugins/fish-spec/spec.run.fish b/plugins/fish-spec/spec.run.fish new file mode 100644 index 0000000..0a9df6f --- /dev/null +++ b/plugins/fish-spec/spec.run.fish @@ -0,0 +1,65 @@ +# NAME +# spec.run - run suite of tests +# +# SYNOPSIS +# spec.run [-v --verbose] +# +# DESCRIPTION +# In order to run tests create the test file, import plugins/spec at +# before adding any of the functions described above and call spec.run. +# +# FUNCTIONS +# import plugins/spec +# +# function before_all Run before any tests are run. +# function before_each Run before each test. +# function describe_* Use to organize different specs. +# function it_* Use to test your library/plugin. +# function after_each Run after each test. +# function after_all Run after all tests are finished. +# +# EXAMPLES +# import plugins/fish-spec +# function describe_erase +# function before_each +# set -g nums 1 2 3 +# end +# function it_erases_one_item -d "It should erase an item from a list." +# erase 1 --from nums +# expect $nums --to-not-contain 1 +# end +# end +# spec.run --verbose +# +# AUTHORS +# Bruno Pinto <@pfbruno> +# Jorge Bucaran <@bucaran> +#/ +function spec.run + set -l result 0 # Optimism + set -l output "--silent" + if contains -- $argv[1] -v --verbose + set output "" + end + # Run 1 or more topmost describe blocks causing fish to load inmediately + # scoped functions, i.e, those inside any invoked describe_ blocks. + spec.eval describe_ --depth 0 $output + spec.eval before_all $output + for test in (spec.functions "it_") + spec.eval before_each $output + # Stop test execution if an expectation fails. + if not spec.eval $test --unit --depth 1 $output + set result 1 # Flunk + end + + # Make sure to run after_each if test fails. + spec.eval after_each $output + if [ $result -eq 1 ] + # We can safely exit the loop if test fails. + break + end + end + spec.eval after_all $output + + return $result +end diff --git a/plugins/fish-spec/spec/list.erase.spec.fish b/plugins/fish-spec/spec/list.erase.spec.fish new file mode 100644 index 0000000..af6f180 --- /dev/null +++ b/plugins/fish-spec/spec/list.erase.spec.fish @@ -0,0 +1,56 @@ +import plugins/fish-spec + +function describe_list_erase -d "Testing Oh-My-Fish `list.erase` function..." + function before_each + set -g nums_until_10 1 2 3 4 5 6 7 8 9 10 + set -g odds_until_10 1 3 5 7 9 + end + + function it_erases_one_element -d "It should erase an element from a list." + list.erase 1 nums_until_10 + expect $nums_until_10 --to-not-contain 1 + end + + function it_erases_one_element_without_from_option \ + -d "It should erase an element with --from option." + list.erase 1 --from nums_until_10 + expect $nums_until_10 --to-not-contain 1 + end + + function it_erases_one_element_from_multiple_lists \ + -d "It should erase an element from multiple lists." + list.erase 1 --from nums_until_10 odds_until_10 + expect $nums_until_10 --to-not-contain 1 + and expect $odds_until_10 --to-not-contain 1 + end + + function it_erases_one_element_from_multiple_lists_when_only_one_has_the_element \ + -d "It should erase an element from multiple lists when only one has the element." + list.erase 2 --from nums_until_10 odds_until_10 + expect $nums_until_10 --to-not-contain 2 + end + + function it_erases_multiple_elements \ + -d "It should erase multiple elements." + list.erase 1 2 nums_until_10 + expect $nums_until_10 --to-not-contain 1 + and expect $nums_until_10 --to-not-contain 2 + end + + function it_erases_multiple_elements_with_from_syntax \ + -d "It should erase multiple elements with --from option." + list.erase 1 2 --from nums_until_10 + expect $nums_until_10 --to-not-contain 1 + and expect $nums_until_10 --to-not-contain 2 + end + + function it_erases_multiple_elements_from_multiple_lists \ + -d "It should erase multiple elements from multiple lists." + list.erase 1 2 --from nums_until_10 odds_until_10 + expect $nums_until_10 --to-not-contain 1 + and expect $nums_until_10 --to-not-contain 2 + and expect $odds_until_10 --to-not-contain 1 + end +end + +spec.run $argv diff --git a/plugins/fish-spec/test/list.erase.test.fish b/plugins/fish-spec/test/list.erase.test.fish deleted file mode 100644 index af435e3..0000000 --- a/plugins/fish-spec/test/list.erase.test.fish +++ /dev/null @@ -1,48 +0,0 @@ -function describe_list_erase - function before_each - set -g nums_until_10 1 2 3 4 5 6 7 8 9 10 - set -g odds_until_10 1 3 5 7 9 - end - - function it_erases_one_element - list.erase 1 nums_until_10 - expect $nums_until_10 to_not_include 1 - end - - function it_erases_one_element_with_from_syntax - list.erase 1 --from nums_until_10 - expect $nums_until_10 to_not_include 1 - end - - function it_erases_one_element_from_multiple_lists - list.erase 1 --from nums_until_10 odds_until_10 - expect $nums_until_10 to_not_include 1 and - expect $odds_until_10 to_not_include 1 - end - - function it_erases_one_element_from_multiple_lists_when_only_one_has_the_element - list.erase 2 --from nums_until_10 odds_until_10 - expect $nums_until_10 to_not_include 2 - end - - function it_erases_multiple_elements - list.erase 1 2 nums_until_10 - expect $nums_until_10 to_not_include 1 and - expect $nums_until_10 to_not_include 2 - end - - function it_erases_multiple_elements_with_from_syntax - list.erase 1 2 --from nums_until_10 - expect $nums_until_10 to_not_include 1 and - expect $nums_until_10 to_not_include 2 - end - - function it_erases_multiple_elements_from_multiple_lists - list.erase 1 2 --from nums_until_10 odds_until_10 - expect $nums_until_10 to_not_include 1 and - expect $nums_until_10 to_not_include 2 and - expect $odds_until_10 to_not_include 1 - end -end - -import plugins/fish-spec diff --git a/spec/oh-my-fish.spec.fish b/spec/oh-my-fish.spec.fish new file mode 100755 index 0000000..a9a5aaf --- /dev/null +++ b/spec/oh-my-fish.spec.fish @@ -0,0 +1,79 @@ +import plugins/fish-spec + +function describe_oh_my_fish -d "Oh-My-Fish test spec..." + function before_all + set -g fish_custom_bak $fish_custom + set -g fish_plugins_bak $fish_plugins + set -g fish_function_path_bak $fish_function_path + end + + function after_all + set fish_custom $fish_custom_bak + set fish_plugins $fish_plugins_bak + set fish_function_path $fish_function_path_bak + end + + function it_has_a_default_custom_directory \ + -d "It should have a default custom directory" + + set -e fish_custom + load_oh_my_fish + expect $fish_custom --to-eq "$HOME/.oh-my-fish/custom" + end + + function it_allows_the_custom_folder_location_to_be_customized \ + -d "It should allow modifying the location of the custom directory" + + set -g fish_custom /tmp + load_oh_my_fish + expect $fish_custom --to-eq '/tmp' + end + + function it_loads_all_custom_files \ + -d "It should load all custom files" + + set -g fish_custom /tmp + echo 'set -gx TEST_LOAD_CUSTOM_FILE file_loaded' > $fish_custom/test.load + + load_oh_my_fish + expect $TEST_LOAD_CUSTOM_FILE --to-eq 'file_loaded' + end + + function it_loads_all_oh_my_fish_functions \ + -d "It should load all default functions" + + list.erase "$fish_path/functions/" --from fish_function_path + + load_oh_my_fish + expect $fish_function_path --to-contain $fish_path/functions/ + end + + function it_loads_all_selected_plugins \ + -d "It should load all user selected plugins" + + list.erase "$fish_path/plugins/bak" \ + "$fish_path/plugins/z" --from fish_function_path + + set -g fish_plugins bak z + load_oh_my_fish + expect $fish_function_path --to-contain $fish_path/plugins/bak + and expect $fish_function_path --to-contain $fish_path/plugins/z + end + + function it_loads_the_selected_theme \ + -d "It should load the user selected theme" + + list.erase "$fish_path/themes/l" --from fish_function_path + + set fish_theme l + load_oh_my_fish + expect $fish_function_path --to-contain $fish_path/themes/l + end +end + +function load_oh_my_fish + . $fish_path/oh-my-fish.fish +end + +# Begin test suite ❯❯❯ +spec.run $argv diff --git a/test/oh_my_fish.test.fish b/test/oh_my_fish.test.fish deleted file mode 100644 index a2dabdb..0000000 --- a/test/oh_my_fish.test.fish +++ /dev/null @@ -1,73 +0,0 @@ -function describe_oh_my_fish - function before_each - set -g fish_custom_bak $fish_custom - set -g fish_function_path_bak $fish_function_path - set -g fish_plugins_bak $fish_plugins - - set -e fish_custom - end - - function after_each - set fish_custom $fish_custom_bak - set fish_function_path $fish_function_path_bak - set fish_plugins $fish_plugins_bak - end - - function it_has_a_default_custom_folder - set -e fish_custom - load_oh_my_fish - expect $fish_custom to_equal "$HOME/.oh-my-fish/custom" - end - - function it_allows_the_custom_folder_location_to_be_customized - set -g fish_custom /tmp - load_oh_my_fish - expect $fish_custom to_equal '/tmp' - end - - function it_loads_all_custom_files - set -g fish_custom /tmp - echo 'set -gx TEST_LOAD_CUSTOM_FILE file_loaded' > $fish_custom/test.load - - load_oh_my_fish - expect $TEST_LOAD_CUSTOM_FILE to_equal 'file_loaded' - end - - function it_loads_all_oh_my_fish_functions - list.erase "$fish_path/functions/" --from fish_function_path - - load_oh_my_fish - expect $fish_function_path to_include $fish_path/functions/ - end - - function it_loads_all_selected_plugins - list.erase "$fish_path/plugins/bak" "$fish_path/plugins/z" --from fish_function_path - - set fish_plugins bak z - load_oh_my_fish - expect $fish_function_path to_include $fish_path/plugins/bak and - expect $fish_function_path to_include $fish_path/plugins/z - end - - function it_loads_plugins_from_custom_folder - list.erase "$fish_custom/plugins/example" --from fish_function_path - - set fish_plugins example - load_oh_my_fish - expect $fish_function_path to_include $fish_custom/plugins/example - end - - function it_loads_the_selected_theme - list.erase "$fish_path/themes/l" --from fish_function_path - - set fish_theme l - load_oh_my_fish - expect $fish_function_path to_include $fish_path/themes/l - end -end - -function load_oh_my_fish - . $fish_path/oh-my-fish.fish -end - -import plugins/fish-spec