Skip to content

codegourmet/structure_compare

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

structure_compare

Compares the structure of two deep nested Ruby structures

General

Use case: you're writing an API response or a JSON export and want to unit test it. Optionally you can ignore the leaf values or any hash key types/order (see below).

Gives error results with the path to where exactly the structures differ.

This README file is mirrored on my blog

Installation

gem install structure_compare

or add it to your Gemfile:

gem structure_compare

quick-n-dirty example:

require 'structure_compare'
comparison = StructureCompare::StructureComparison.new

expected = { a: 1, b: 2, c: [1, 2, 3] }
actual   = { a: 1, b: 2, c: [1, 2, "A"] }

comparison.structures_are_equal?(expected, actual)
puts comparison.error
# => root[:c][2] : expected String to be kind of Fixnum

MiniTest

require 'structure_compare'
require 'structure_compare/minitest'

assert_structures_equal({ a: 1, b: 2 }, { a: 1, b: 2 })
refute_structures_equal({ a: 1, b: 2 }, { c: 1, d: 2 })

Options

Strict key ordering

name: strict_key_order (default: false)

expected = { a: 1, b: 2 }
actual   = { b: 2, a: 1 }

comparison = StructureCompare::StructureComparison.new(strict_key_order: false)
comparison.structures_are_equal?(expected, actual)
# => true

Value checking

name: check_values (default: true)

expected = { a: 1, b: { c: 1 } }
actual   = { a: 8, b: { c: 8 } }

comparison = StructureCompare::StructureComparison.new
comparison.structures_are_equal?(expected, actual)
# => false

comparison = StructureCompare::StructureComparison.new(check_values: false)
comparison.structures_are_equal?(expected, actual)
# => true

Indifferent Access

Hash symbol keys are treated as equal to string keys

NOTE: an exception will be raised if there's a key present as symbol and string

name: indifferent_access (default: false)

expected = { a: 1 }
actual   = { "a" => 1 }

comparison = StructureCompare::StructureComparison.new
comparison.structures_are_equal?(expected, actual)
# => false

comparison = StructureCompare::StructureComparison.new(indifferent_access: true)
comparison.structures_are_equal?(expected, actual)
# => true

hash = { a: 1, "a" => 2 }
comparison = StructureCompare::StructureComparison.new(indifferent_access: true)
comparison.structures_are_equal?(hash, hash)
# => StructureCompare::IndifferentAccessError

Float tolerance

When dealing with floats, you will want to introduce a tolerance.

NOTE: Float::EPSILON is always used for comparing Float type values.

NOTE: The check_values option must be set.

name: float_tolerance_factor (default: 0)

tolerance = +- (expected * (1.0 + tolerance_factor) + Float::EPSILON)

This means a float_tolerance_factor setting of 0.01 means that actual can be 1% different from expected to still be treated equal.

expected = { a: 10.0 }
actual_1 = { a: 10.1 }
actual_2 = { a: 10.11 }

# 1% tolerance factor
comparison = StructureCompare::StructureComparison.new(
  float_tolerance_factor: 0.01, check_values: true
)
comparison.structures_are_equal?(expected, actual_1)
# => true

comparison.structures_are_equal?(expected, actual_2)
# => false

TODOS

RSpec helpers. Refactoring.

Contributing

Fork me and send me a pull request with your feature and working tests, or just request a feature.

License

MIT License, see LICENSE file in the root directory

About

Compares the structure of two deeply nested Ruby structures

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages