Class: Kumi::Dev::Golden::ValueNormalizer

Inherits:
Object
  • Object
show all
Defined in:
lib/kumi/dev/golden/value_normalizer.rb

Overview

Normalizes values for test comparisons, handling decimal precision

Class Method Summary collapse

Class Method Details

.compare_values(actual, expected, language:) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/kumi/dev/golden/value_normalizer.rb', line 40

def self.compare_values(actual, expected, language:)
  # Handle decimal comparisons with tolerance for floating-point errors
  case [actual, expected]
  in [Array, Array]
    actual.length == expected.length &&
      actual.zip(expected).all? { |a, e| compare_values(a, e, language: language) }
  in [Hash, Hash]
    actual.keys == expected.keys &&
      actual.all? { |k, v| compare_values(v, expected[k], language: language) }
  in [BigDecimal, BigDecimal]
    actual == expected
  in [BigDecimal, (Integer | Float)]
    BigDecimal(actual.to_s) == BigDecimal(expected.to_s)
  in [(Integer | Float), BigDecimal]
    BigDecimal(actual.to_s) == BigDecimal(expected.to_s)
  in [(Integer | Float), String] | [String, (Integer | Float)]
    # Compare number with decimal string (e.g., JavaScript number vs expected string)
    actual_bd = BigDecimal(actual.to_s)
    expected_bd = BigDecimal(expected.to_s)
    # Allow small floating-point differences (within 1e-10)
    (actual_bd - expected_bd).abs < BigDecimal("1e-10")
  in [String, String]
    # Both strings - try to parse as decimals and compare
    begin
      actual_bd = BigDecimal(actual)
      expected_bd = BigDecimal(expected)
      (actual_bd - expected_bd).abs < BigDecimal("1e-10")
    rescue ArgumentError
      # If not valid decimals, compare as strings
      actual == expected
    end
  else
    actual == expected
  end
end

.decimal_string?(str) ⇒ Boolean



35
36
37
38
# File 'lib/kumi/dev/golden/value_normalizer.rb', line 35

def self.decimal_string?(str)
  # Match decimal number strings like "10.50", "123", "-45.67"
  str.match?(/\A-?\d+(\.\d+)?\z/)
end

.normalize(value, language: :ruby) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/kumi/dev/golden/value_normalizer.rb', line 10

def self.normalize(value, language: :ruby)
  case value
  when Hash
    value.transform_values { |v| normalize(v, language: language) }
  when Array
    value.map { |v| normalize(v, language: language) }
  when String
    # Try to parse as decimal if it looks like one
    if decimal_string?(value)
      language == :ruby ? BigDecimal(value) : value
    else
      value
    end
  else
    value
  end
end

.values_equal?(actual, expected, language: :ruby) ⇒ Boolean



28
29
30
31
32
33
# File 'lib/kumi/dev/golden/value_normalizer.rb', line 28

def self.values_equal?(actual, expected, language: :ruby)
  norm_actual = normalize(actual, language: language)
  norm_expected = normalize(expected, language: language)

  compare_values(norm_actual, norm_expected, language: language)
end