class Oktest::JsonMatcher

Public Instance Methods

===(expected) click to toggle source
# File lib/oktest.rb, line 582
def ===(expected)
  #; [!4uf1o] raises assertion error when JSON not matched.
  _compare([], @actual, expected)
  #; [!0g0u4] returns true when JSON matched.
  return true
end

Private Instance Methods

_compare(path, a, e) click to toggle source
# File lib/oktest.rb, line 600
def _compare(path, a, e)
  if a.is_a?(Hash) && e.is_a?(Hash)
    _compare_hash(path, a, e)
  elsif a.is_a?(Array) && e.is_a?(Array)
    _compare_array(path, a, e)
  elsif e.is_a?(Enumerator)
    _compare_enumerator(path, a, e)
  elsif e.is_a?(OR)
    _compare_or(path, a, e)
  elsif e.is_a?(AND)
    _compare_and(path, a, e)
  else
    _compare_value(path, a, e)
  end
end
_compare?(path, a, e) click to toggle source
# File lib/oktest.rb, line 591
def _compare?(path, a, e)
  #; [!nkvqo] returns true when nothing raised.
  #; [!57m2j] returns false when assertion error raised.
  _compare(path, a, e)
  return true
rescue FAIL_EXCEPTION
  return false
end
_compare_and(path, a, e) click to toggle source
# File lib/oktest.rb, line 720
    def _compare_and(path, a, e)
      #; [!4hk96] `AND()` matches to all of arguments.
      #; [!scx22] `AND()` can contain `OR()`.
      failed = e.items.find {|e2| ! _compare?(path, a, e2) }
      ! failed  or fail <<"END"
$<JSON>#{_path(path)}: $<expected> === $<actual> : failed.
    $<actual>:   #{a.inspect}
    $<expected>: AND(#{failed.inspect})
END
    end
_compare_array(path, a, e) click to toggle source
# File lib/oktest.rb, line 638
    def _compare_array(path, a, e)
      #; [!bz74w] fails when array lengths are different.
      a.length == e.length  or fail <<"END"
$<JSON>#{_path(path)}: $<actual>.length == $<expected>.length : failed.
    $<actual>.length:   #{a.length}
    $<expected>.length: #{e.length}
    $<actual>:   #{a.inspect}
    $<expected>: #{e.inspect}
END
      #; [!lh6d6] compares array items recursively.
      path.push(nil)
      i = -1
      a.zip(e) do |a2, e2|
        path[-1] = (i += 1)
        _compare(path, a2, e2)
      end
      path.pop()
    end
_compare_enumerator(path, a, e) click to toggle source
# File lib/oktest.rb, line 692
    def _compare_enumerator(path, a, e)
      #; [!ljrmc] fails when expected is an Enumerator object and actual is not an array.
      e2 = e.first
      a.is_a?(Array)  or fail <<"END"
$<JSON>#{_path(path)}: Array value expected but got #{a.class.name} value.
    $<actual>:   #{a.inspect}
    $<expected>: [#{e2.inspect}].each
END
      #; [!sh5cg] Enumerator object matches to repeat of rule.
      path.push(nil)
      a.each_with_index do |a2, i|
        path[-1] = i
        _compare(path, a2, e2)
      end
      path.pop()
    end
_compare_hash(path, a, e) click to toggle source
# File lib/oktest.rb, line 657
    def _compare_hash(path, a, e)
      #; [!rkv0z] compares two hashes with converting keys into string.
      a2 = {}; a.each {|k, v| a2[k.to_s] = v }
      e2 = {}; e.each {|k, v| e2[k.to_s] = v }
      #; [!fmxyg] compares hash objects recursively.
      path.push(nil)
      a2.each_key do |k|
        path[-1] = k
        if e2.key?(k)
          _compare(path, a2[k], e2[k])
        #; [!jbyv6] key 'aaa?' represents optional key.
        elsif e2.key?("#{k}?")
          _compare(path, a2[k], e2["#{k}?"]) unless a2[k].nil?
        #; [!uc4ag] key '*' matches to any key name.
        elsif e2.key?("*")
          _compare(path, a2[k], e2["*"])
        #; [!mpbvu] fails when unexpected key exists in actual hash.
        else
          fail <<"END"
$<JSON>#{_path(path)}: unexpected key.
    $<actual>:   #{a2[k].inspect}
END
        end
      end
      path.pop()
      #; [!4oasq] fails when expected key not exist in actual hash.
      (e2.keys - a2.keys).each do |k|
        k =~ /\?\z/ || k == "*"  or fail <<"END"
$<JSON>#{_path(path)}: key \"#{k}\" expected but not found.
    $<actual>.keys:   #{a2.keys.sort.inspect[1...-1]}
    $<expected>.keys: #{e2.keys.sort.inspect[1...-1]}
END
      end
    end
_compare_or(path, a, e) click to toggle source
# File lib/oktest.rb, line 709
    def _compare_or(path, a, e)
      #; [!eqr3b] `OR()` matches to any of arguments.
      #; [!5ybfg] `OR()` can contain `AND()`.
      passed = e.items.any? {|e2| _compare?(path, a, e2) }
      passed  or fail <<"END"
$<JSON>#{_path(path)}: $<expected> === $<actual> : failed.
    $<actual>:   #{a.inspect}
    $<expected>: OR(#{e.items.collect(&:inspect).join(', ')})
END
    end
_compare_value(path, a, e) click to toggle source
# File lib/oktest.rb, line 616
    def _compare_value(path, a, e)
      #; [!1ukbv] scalar value matches to integer, string, bool, and so son.
      #; [!8o55d] class object matches to instance object.
      #; [!s625d] regexp object matches to string value.
      #; [!aqkk0] range object matches to scalar value.
      #; [!a7bfs] Set object matches to enum value.
      e === a  or fail <<"END"
$<JSON>#{_path(path)}: $<expected> === $<actual> : failed.
    $<actual>:   #{a.inspect}
    $<expected>: #{e.inspect}
END
      #; [!4ymj2] fails when actual value is not matched to item class of range object.
      if e.is_a?(Range)
        expected_class = (e.begin || e.end).class
        a.is_a?(expected_class)  or fail <<"END"
$<JSON>#{_path(path)}: expected #{expected_class.name} value, but got #{a.class.name} value.
    $<actual>:   #{a.inspect}
    $<expected>: #{e.inspect}
END
      end
    end
_path(path) click to toggle source
# File lib/oktest.rb, line 731
def _path(path)
  #return path.collect {|x| "/#{x}" }.join()
  return path.collect {|x| "[#{x.inspect}]" }.join()
end