Skip to content

Instantly share code, notes, and snippets.

@Overbryd
Last active June 2, 2022 10:27
Show Gist options
  • Select an option

  • Save Overbryd/b4ea6ec28f4ff9d2a65f to your computer and use it in GitHub Desktop.

Select an option

Save Overbryd/b4ea6ec28f4ff9d2a65f to your computer and use it in GitHub Desktop.

Revisions

  1. Overbryd revised this gist Apr 20, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -39,6 +39,7 @@ def assert_structure(expectation, object)
    path << "[ "
    assert_kind_of(Array, object)
    next unless expectation = expectation.first
    refute_empty(object, "Structure does not match in: #{path}")
    object.each_with_index do |element, index|
    stack << [expectation, element, path + "#{index} => "]
    end
  2. Overbryd revised this gist Apr 20, 2015. 1 changed file with 7 additions and 6 deletions.
    13 changes: 7 additions & 6 deletions assert_xml_structure.rb
    Original file line number Diff line number Diff line change
    @@ -6,12 +6,13 @@ module MiniTest::Assertions
    # The hash will be traversed, each key is a XPATH expression, each value either an expectation or another nested structure
    #
    # Possible values:
    # :_something_ - can be used as a non-nil wildcard, useful for checking the existance of a key
    # [] - can be used as not existing, useful for checking if an XPATH returns an empty array
    # /regexp/ - useful for checking on text of the tested node
    # String - can be used for asserting some non blank text is set at the node
    # [{structure}] - an array with one structure definition can be used for asserting the structure of the children nodes
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    # :_something_ - can be used as a non-nil wildcard, useful for checking the existance of a key
    # [] - can be used as not existing, useful for checking if an XPATH returns an empty array
    # /regexp/ - useful for checking on text of the tested node
    # String - can be used for asserting some non blank text is set at the node
    # "string value" - can be used for asserting a nodes text is equal to the given string
    # [{structure}] - an array with one structure definition can be used for asserting the structure of the children nodes
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    def assert_xml_structure(expectation, xml)
    xml = Nokogiri.XML(xml) { |config| config.noblanks } if xml.is_a?(String)
    stack = [[expectation, xml, ""]]
  3. Overbryd renamed this gist Apr 20, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. Overbryd revised this gist Apr 20, 2015. 1 changed file with 58 additions and 0 deletions.
    58 changes: 58 additions & 0 deletions assert_xml_structure.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    module MiniTest::Assertions

    # assert_xml_structure(expectation, xml)
    # will inspect the given object or string (second argument) and match with the structure definition (first argument)
    # As structure a hash should be supplied
    # The hash will be traversed, each key is a XPATH expression, each value either an expectation or another nested structure
    #
    # Possible values:
    # :_something_ - can be used as a non-nil wildcard, useful for checking the existance of a key
    # [] - can be used as not existing, useful for checking if an XPATH returns an empty array
    # /regexp/ - useful for checking on text of the tested node
    # String - can be used for asserting some non blank text is set at the node
    # [{structure}] - an array with one structure definition can be used for asserting the structure of the children nodes
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    def assert_xml_structure(expectation, xml)
    xml = Nokogiri.XML(xml) { |config| config.noblanks } if xml.is_a?(String)
    stack = [[expectation, xml, ""]]
    until (expectation, xml, path = *stack.pop).empty? do
    case expectation
    when :_something_
    path << "something"
    refute_equal(nil, xml.empty?, "Structure does not match in: #{path}")
    when Regexp
    path << "match(#{expectation.inspect})"
    assert_match(expectation, xml.text, "Structure does not match in: #{path}")
    when Proc
    path << "#{expectation.lambda? ? "lambda" : "proc"}"
    assert(expectation.call(xml), "Structure does not match in: #{path}")
    when Hash
    path << "{ "
    expectation.each do |key, expected|
    stack << [expected, xml.xpath(key), path + "#{key} => "]
    end
    when Array
    path << "[ "
    if structure = expectation.first
    xml.children.each_with_index do |child, index|
    stack << [expectation, child, path + "#{index} => "]
    end
    else
    assert_empty(xml, "Structure does not match in: #{path}")
    end
    when Class
    if expectation == String
    path << "string"
    refute(xml.text.blank?, "Structure does not match in: #{path}")
    end
    when String
    path << "equal(#{expectation.inspect})"
    assert_equal(expectation, xml.text, "Structure does not match in: #{path}")
    else
    path << "equal(#{expectation.inspect})"
    assert_equal(expectation, xml, "Structure does not match in: #{path}")
    end
    end
    end

    end
  5. Overbryd revised this gist Apr 20, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -15,8 +15,8 @@ module MiniTest::Assertions
    # any class - can be used for asserting the type
    # any value - can be used for asserting the actual value
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    def assert_structure(expectation, object, path = "")
    stack = [[expectation, object, path]]
    def assert_structure(expectation, object)
    stack = [[expectation, object, ""]]
    until (expectation, object, path = *stack.pop).empty? do
    case expectation
    when :_something_
  6. Overbryd revised this gist Apr 20, 2015. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -10,10 +10,11 @@ module MiniTest::Assertions
    #
    # Possible values for any given structure:
    # :_something_ - can be used as a non-nil wildcard, useful for checking the existance of a key
    # nil - can be used as not existing, useful for checking if a key is set or not
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    # any class - can be used for asserting the type
    # any value - can be used for asserting the actual value
    # nil - can be used as not existing, useful for checking if a key is set or not
    # /regexp/ - useful for checking on parts of the values
    # any class - can be used for asserting the type
    # any value - can be used for asserting the actual value
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    def assert_structure(expectation, object, path = "")
    stack = [[expectation, object, path]]
    until (expectation, object, path = *stack.pop).empty? do
  7. Overbryd revised this gist Apr 20, 2015. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -20,13 +20,17 @@ def assert_structure(expectation, object, path = "")
    case expectation
    when :_something_
    path << "something"
    refute_equal nil, object, "Structure does not match in: #{path}'"
    refute_equal(nil, object, "Structure does not match in: #{path}")
    when Regexp
    path << "match(#{expectation.inspect})"
    assert_kind_of(String, object, "Structure does not match in: #{path}")
    assert_match(expectation, object, "Structure does not match in: #{path}")
    when Proc
    path << "#{expectation.lambda? ? "lambda" : "proc"}"
    assert expectation.call(object), "Structure does not match in: #{path}'"
    assert(expectation.call(object), "Structure does not match in: #{path}")
    when Hash
    path << "{ "
    assert_kind_of(Hash, object, "Structure does not match in: #{path}'")
    assert_kind_of(Hash, object, "Structure does not match in: #{path}")
    expectation.each do |key, expected|
    stack << [expected, object[key], path + "#{key.inspect} => "]
    end
    @@ -47,5 +51,4 @@ def assert_structure(expectation, object, path = "")
    end
    end


    end
  8. Overbryd revised this gist Apr 20, 2015. 1 changed file with 12 additions and 5 deletions.
    17 changes: 12 additions & 5 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -14,13 +14,19 @@ module MiniTest::Assertions
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    # any class - can be used for asserting the type
    # any value - can be used for asserting the actual value
    def assert_structure(expectation, object)
    stack = [[expectation, object, ""]]
    def assert_structure(expectation, object, path = "")
    stack = [[expectation, object, path]]
    until (expectation, object, path = *stack.pop).empty? do
    case expectation
    when :_something_
    path << "something"
    refute_equal nil, object, "Structure does not match in: #{path}'"
    when Proc
    path << "#{expectation.lambda? ? "lambda" : "proc"}"
    assert expectation.call(object), "Structure does not match in: #{path}'"
    when Hash
    path << "{ "
    assert_kind_of(Hash, object, "Structure does not match in `#{path}'")
    assert_kind_of(Hash, object, "Structure does not match in: #{path}'")
    expectation.each do |key, expected|
    stack << [expected, object[key], path + "#{key.inspect} => "]
    end
    @@ -33,12 +39,13 @@ def assert_structure(expectation, object)
    end
    when Class
    path << "kind_of(#{expectation.name})"
    assert_kind_of(expectation, object, "Structure does not match in `#{path}")
    assert_kind_of(expectation, object, "Structure does not match in: #{path}")
    else
    path << "equal(#{expectation.inspect})"
    assert_equal(expectation, object, "Structure does not match in `#{path}")
    assert_equal(expectation, object, "Structure does not match in: #{path}")
    end
    end
    end


    end
  9. Overbryd created this gist Apr 20, 2015.
    44 changes: 44 additions & 0 deletions assert_structure.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    module MiniTest::Assertions

    # assert_structure(expectation, object)
    # will inspect the given object (second argument) and match with the structure definition (first argument).
    # As structure a Hash or an Array can be supplied
    # Hash will be matched for their keys and values
    # Arrays will be matched for being an array and optionally traversed so that each element matches a given structure
    #
    # This _is_ the holy grail of API response testing.
    #
    # Possible values for any given structure:
    # :_something_ - can be used as a non-nil wildcard, useful for checking the existance of a key
    # nil - can be used as not existing, useful for checking if a key is set or not
    # lambda - can be used for your own code, will be given the value and expects a boolean return value
    # any class - can be used for asserting the type
    # any value - can be used for asserting the actual value
    def assert_structure(expectation, object)
    stack = [[expectation, object, ""]]
    until (expectation, object, path = *stack.pop).empty? do
    case expectation
    when Hash
    path << "{ "
    assert_kind_of(Hash, object, "Structure does not match in `#{path}'")
    expectation.each do |key, expected|
    stack << [expected, object[key], path + "#{key.inspect} => "]
    end
    when Array
    path << "[ "
    assert_kind_of(Array, object)
    next unless expectation = expectation.first
    object.each_with_index do |element, index|
    stack << [expectation, element, path + "#{index} => "]
    end
    when Class
    path << "kind_of(#{expectation.name})"
    assert_kind_of(expectation, object, "Structure does not match in `#{path}")
    else
    path << "equal(#{expectation.inspect})"
    assert_equal(expectation, object, "Structure does not match in `#{path}")
    end
    end
    end

    end
    53 changes: 53 additions & 0 deletions examples.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,53 @@
    # lets say this is the response we receive
    response = {
    "results" => {
    "total_count" => 15,
    "per_page" => 100,
    "companies" => [
    {
    "company" => {
    "name" => "Foo Bar Ltd",
    "registered_address" => { ... },
    ...
    }
    },
    {
    "company" => {
    "name" => "Zig Zag Inc",
    "registered_address" => { ... },
    ...
    }
    },
    {
    "company" => {
    "name" => "Meh Bleh",
    "registered_address" => { ... },
    # BOOM! We expect each object in this array not have a registered_address_in_full
    "registered_address_in_full" => "Foobargl",
    ...
    }
    }
    ...
    ]
    }
    }

    assert_structure({
    "results" => { # assert there is a results hash
    "companies" => [ # with a key 'companies' holding an array
    { # each element being a hash
    "company" => { # with a key 'company' holding a hash
    "name" => String, # with a key 'name' of type String
    "registered_address_in_full" => nil # without a key 'registered_address_in_full'
    }
    }
    ]
    }
    }, response)

    # This will give super nice and awesome error messages like:
    #
    # Structure does not match in: { "results" => { "companies" => [ 2 => { "company" => { "registered_address_in_full" => equal(nil).
    #
    # HELL YEA!
    # Now you can exactly understand where and what broke!