Permalink
Browse files

Merge branch 'custom-failure-message'

Close gh-8, gh-11.
  • Loading branch information...
2 parents 7f1b070 + fb166da commit 707b5cde0762a0b4f4c5708b2ccf7bf6902859bf @kana committed Oct 29, 2012
Showing with 290 additions and 37 deletions.
  1. +77 −15 autoload/vspec.vim
  2. +44 −10 doc/vspec.txt
  3. +12 −2 t/builtin-matchers.vim
  4. +105 −0 t/custom-failure-message.t
  5. +48 −6 t/custom-matchers.vim
  6. +2 −2 t/expect.vim
  7. +2 −2 t/tools.vim
View
@@ -49,7 +49,7 @@ let s:current_suites = [] "{{{2
let s:custom_matchers = {} "{{{2
-" :: MatcherNameString -> Funcref
+" :: MatcherNameString -> Matcher
@@ -149,8 +149,13 @@ endfunction
-function! vspec#customize_matcher(matcher_name, funcref) "{{{2
- let s:custom_matchers[a:matcher_name] = a:funcref
+function! vspec#customize_matcher(matcher_name, maybe_matcher) "{{{2
+ if type(a:maybe_matcher) == type({})
+ let matcher = a:maybe_matcher
+ else
+ let matcher = {'match': a:maybe_matcher}
+ endif
+ let s:custom_matchers[a:matcher_name] = matcher
endfunction
@@ -235,11 +240,15 @@ function! vspec#test(specfile_path) "{{{2
\ suite.subject,
\ example
\ )
- echo '# Expected' i.expr_actual i.expr_matcher i.expr_expected
- echo '# Actual value:' string(i.value_actual)
- if !s:is_custom_matcher(i.expr_matcher)
- echo '# Expected value:' string(i.value_expected)
- endif
+ echo '# Expected' join(filter([
+ \ i.expr_actual,
+ \ i.expr_not,
+ \ i.expr_matcher,
+ \ i.expr_expected,
+ \ ], 'v:val != ""'))
+ for line in s:generate_failure_message(i)
+ echo '# ' . line
+ endfor
elseif type ==# 'TODO'
echo printf(
\ '%s %d - # TODO %s %s',
@@ -301,19 +310,21 @@ endfunction
-" Predefined custom matchers - toBeFalse "{{{2
+" Predefined custom matchers - to_be_false "{{{2
function! vspec#_matcher_false(value)
return type(a:value) == type(0) ? !(a:value) : s:FALSE
endfunction
+call vspec#customize_matcher('to_be_false', function('vspec#_matcher_false'))
call vspec#customize_matcher('toBeFalse', function('vspec#_matcher_false'))
-" Predefined custom matchers - toBeTrue "{{{2
+" Predefined custom matchers - to_be_true "{{{2
function! vspec#_matcher_true(value)
return type(a:value) == type(0) ? !!(a:value) : s:FALSE
endfunction
+call vspec#customize_matcher('to_be_true', function('vspec#_matcher_true'))
call vspec#customize_matcher('toBeTrue', function('vspec#_matcher_true'))
@@ -516,7 +527,7 @@ function! s:parse_should_arguments(s, mode) "{{{2
let matcher = string(_matcher)
endif
if s:is_custom_matcher(_matcher)
- let expected = string(_expected)
+ let expected = '[' . _expected . ']'
endif
let not = string(_not)
endif
@@ -589,14 +600,22 @@ let s:VALID_MATCHERS = (s:VALID_MATCHERS_EQUALITY
function! s:are_matched(value_actual, expr_matcher, value_expected) "{{{2
if s:is_custom_matcher(a:expr_matcher)
let custom_matcher_name = a:expr_matcher
- if !has_key(s:custom_matchers, custom_matcher_name)
+ let matcher = get(s:custom_matchers, custom_matcher_name, 0)
+ if matcher is 0
throw
\ 'vspec:InvalidOperation:Unknown custom matcher - '
\ . string(custom_matcher_name)
endif
+ let Match = get(matcher, 'match', 0)
+ if Match is 0
+ throw
+ \ 'vspec:InvalidOperation:Custom matcher does not have match function - '
+ \ . string(custom_matcher_name)
+ endif
return !!call(
- \ s:custom_matchers[custom_matcher_name],
- \ [a:value_actual] + eval(printf('[%s]', a:value_expected))
+ \ Match,
+ \ [a:value_actual] + a:value_expected,
+ \ matcher
\ )
elseif s:is_equality_matcher(a:expr_matcher)
let type_equality = type(a:value_actual) == type(a:value_expected)
@@ -625,6 +644,49 @@ endfunction
+function! s:generate_default_failure_message(i) "{{{2
+ return [
+ \ ' Actual value: ' . string(a:i.value_actual),
+ \ 'Expected value: ' . string(a:i.value_expected),
+ \ ]
+endfunction
+
+
+
+
+function! s:generate_failure_message(i) "{{{2
+ let matcher = get(s:custom_matchers, a:i.value_matcher, 0)
+ if matcher is 0
+ return s:generate_default_failure_message(a:i)
+ else
+ let method_name =
+ \ a:i.value_not == ''
+ \ ? 'failure_message_for_should'
+ \ : 'failure_message_for_should_not'
+ let Generate = get(
+ \ matcher,
+ \ method_name,
+ \ 0
+ \ )
+ if Generate is 0
+ return s:generate_default_failure_message(a:i)
+ else
+ let values = [a:i.value_actual]
+ if a:i.expr_expected != ''
+ call extend(values, a:i.value_expected)
+ endif
+ let maybe_message = call(Generate, values, matcher)
+ return
+ \ type(maybe_message) == type('')
+ \ ? [maybe_message]
+ \ : maybe_message
+ endif
+ endif
+endfunction
+
+
+
+
function! s:is_custom_matcher(expr_matcher) "{{{2
return a:expr_matcher =~# '^to'
endfunction
@@ -683,7 +745,7 @@ endfunction
let s:RE_SPLIT_AT_MATCHER =
\ printf(
-\ '\C\v^(.{-})\s+%%((not)\s+)?(%%(%%(%s)[#?]?)|to\w+>)(.*)$',
+\ '\C\v^(.{-})\s+%%((not)\s+)?(%%(%%(%s)[#?]?)|to\w+>)\s*(.*)$',
\ join(
\ map(
\ reverse(sort(copy(s:VALID_MATCHERS))),
View
@@ -143,26 +143,32 @@ COMMANDS *vspec-commands*
Examples:
>
- function! True(actual_value)
+ function! ToBeTrue(actual_value)
return (type(a:actual_value) == type(0)
\ ? a:actual_value
\ : !!0)
endfunction
- call vspec#customize_matcher('toBeTrue',
- \ function('True'))
+ call vspec#customize_matcher(
+ \ 'to_be_true',
+ \ function('ToBeTrue')
+ \ )
- :Expect 123 toBeTrue
+ :Expect 123 to_be_true
" ===> good
- :Expect [123] toBeTrue
+ :Expect [123] to_be_true
" ===> bad
<
*vspec-predefined-custom-matchers*
The following custom matcheres are predefined:
- "toBeTrue"
+ "to_be_true"
Return true if {actual} value is true.
- "toBeFalse"
+ "to_be_false"
Return true if {actual} value is false.
+ "toBeTrue"
+ Same as "to_be_true". Deprecated.
+ "toBeFalse"
+ Same as "to_be_false". Deprecated.
:Expect {actual} not {matcher} {expected} *:Expect-not*
:Expect {actual} not {custom-matcher} [{arg}, ...]
@@ -240,9 +246,37 @@ vspec#call({funcname}, [{arg}, ...]) *vspec#call()*
{arg} is an arbitrary value which is given to the
function corresponding to o{funcname}.
-vspec#customize_matcher({alias}, {function}) *vspec#customize_matcher()*
- Register {function} as a |vspec-custom-matcher| which
- alias is {alias}.
+vspec#customize_matcher({alias}, {matcher}) *vspec#customize_matcher()*
+ Register {matcher} as a |vspec-custom-matcher| with
+ a given {alias}. {alias} should be snake_case.
+
+ {matcher} is a dictionary with the following items:
+
+ "match" (required)
+ A |Funcref| to determine whether {actual}
+ value matches to {expected} value. It takes
+ 1 or more arguments. The first argument is
+ {actual} value given to |:Expect|, and the
+ rest of arguments are arbitrary {expected}
+ values. It returns true if {actual} value is
+ matched to {expected} value, or false
+ otherwise.
+
+ "failure_message_for_should" (optional)
+ A |Funcref| to generate user friendly message
+ for failed match with |:Expect|. It takes
+ arguments the same as "match", and it returns
+ a string or a list of strings to describe
+ a failure.
+
+ "failure_message_for_should_not" (optional)
+ Like "failure_message_for_should", but it is
+ used to generate failure message for
+ |:Expect-not|.
+
+vspec#customize_matcher({alias}, {function}) *vspec#customize_matcher()-old*
+ Deprecated. Use |vspec#customize_matcher()| instead.
+ This style is remiained for backward compatibility.
vspec#hint({info}) *vspec#hint()*
Tell vspec "hint" information to use useful API to
View
@@ -844,15 +844,25 @@ describe 'isnot?'
end
end
-describe 'be false'
+describe 'to_be_false'
it 'should succeed if a given value is false'
+ Expect 0 to_be_false
+ Expect 1 not to_be_false
+ end
+
+ it 'is still available as old style alias'
Expect 0 toBeFalse
Expect 1 not toBeFalse
end
end
-describe 'be true'
+describe 'to_be_true'
it 'should succeed if a given value is true'
+ Expect 0 not to_be_true
+ Expect 1 to_be_true
+ end
+
+ it 'is still available as old style alias'
Expect 0 not toBeTrue
Expect 1 toBeTrue
end
View
@@ -0,0 +1,105 @@
+#!/bin/bash
+
+./t/check-vspec-result <(cat <<'END'
+let s:to_be_empty = {}
+function! s:to_be_empty.match(actual)
+ return empty(a:actual)
+endfunction
+function! s:to_be_empty.failure_message_for_should(actual)
+ return 'Actual value is ' . string(a:actual)
+endfunction
+function! s:to_be_empty.failure_message_for_should_not(actual)
+ return 'Actual value is empty'
+endfunction
+call vspec#customize_matcher('to_be_empty', s:to_be_empty)
+
+let s:to_be_multiple_of = {}
+function! s:to_be_multiple_of.match(actual, n)
+ return a:actual % a:n == 0
+endfunction
+function! s:to_be_multiple_of.failure_message_for_should(actual, n)
+ return 'Actual value is ' . string(a:actual) . ', not multiple of ' . a:n
+endfunction
+function! s:to_be_multiple_of.failure_message_for_should_not(actual, n)
+ return 'Actual value is ' . string(a:actual) . ', multiple of ' . a:n
+endfunction
+call vspec#customize_matcher('to_be_multiple_of', s:to_be_multiple_of)
+
+let s:to_be_surrounded = {}
+function! s:to_be_surrounded.match(actual, l, r)
+ return a:actual[0:0] ==# a:l && a:actual[-1:-1] ==# a:r
+endfunction
+function! s:to_be_surrounded.failure_message_for_should(actual, l, r)
+ return 'Actual value ' . string(a:actual) . ' is not surrounded by ' . a:l . ' and ' . a:r
+endfunction
+function! s:to_be_surrounded.failure_message_for_should_not(actual, l, r)
+ return 'Actual value ' . string(a:actual) . ' is surrounded by ' . a:l . ' and ' . a:r
+endfunction
+call vspec#customize_matcher('to_be_surrounded', s:to_be_surrounded)
+
+describe 'vspec#customize_matcher'
+ it 'supports custom failure message for positive case with 0 argument'
+ let xs = [1]
+ Expect xs to_be_empty
+ end
+
+ it 'supports custom failure message for negative case with 0 argument'
+ let xs = []
+ Expect xs not to_be_empty
+ end
+
+ it 'supports custom failure message for positive case with 1 argument'
+ let m = 17
+ let n = 4
+ Expect m not to_be_multiple_of n
+ Expect m to_be_multiple_of n
+ end
+
+ it 'supports custom failure message for negative case with 1 argument'
+ let m = 16
+ let n = 4
+ Expect m to_be_multiple_of n
+ Expect m not to_be_multiple_of n
+ end
+
+ it 'supports custom failure message for positive case with 2 arguments'
+ let s = '(foo)'
+ let l = '<'
+ let r = '>'
+ Expect s not to_be_surrounded l, r
+ Expect s to_be_surrounded l, r
+ end
+
+ it 'supports custom failure message for negative case with 2 arguments'
+ let s = '(foo)'
+ let l = '('
+ let r = ')'
+ Expect s to_be_surrounded l, r
+ Expect s not to_be_surrounded l, r
+ end
+end
+END
+) <(cat <<'END'
+not ok 1 - vspec#customize_matcher supports custom failure message for positive case with 0 argument
+# Expected xs to_be_empty
+# Actual value is [1]
+not ok 2 - vspec#customize_matcher supports custom failure message for negative case with 0 argument
+# Expected xs not to_be_empty
+# Actual value is empty
+not ok 3 - vspec#customize_matcher supports custom failure message for positive case with 1 argument
+# Expected m to_be_multiple_of n
+# Actual value is 17, not multiple of 4
+not ok 4 - vspec#customize_matcher supports custom failure message for negative case with 1 argument
+# Expected m not to_be_multiple_of n
+# Actual value is 16, multiple of 4
+not ok 5 - vspec#customize_matcher supports custom failure message for positive case with 2 arguments
+# Expected s to_be_surrounded l, r
+# Actual value '(foo)' is not surrounded by < and >
+not ok 6 - vspec#customize_matcher supports custom failure message for negative case with 2 arguments
+# Expected s not to_be_surrounded l, r
+# Actual value '(foo)' is surrounded by ( and )
+1..6
+END
+)
+
+# vim: filetype=sh
Oops, something went wrong.

0 comments on commit 707b5cd

Please sign in to comment.