minitest-attributes 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b71a344c8363a4b9c1e246d0dd780385dd779ba05438732e5bb882d1a81caf29
4
- data.tar.gz: e328c7e05f313934149b2df5e44e63b438aefa5756ca156e762b9f98a637dcbd
3
+ metadata.gz: 40bffe082643608c76743541a2d5407624899216156781110c8dfcfb768c71e4
4
+ data.tar.gz: 0b8d08ab75ba4b13c4f9ccefc3801f1b4fd7fbd5556f1d4ff5cd217144eba55d
5
5
  SHA512:
6
- metadata.gz: 9eaab64b6f06377a1021efd511c94e6a226a42c3bf9ef1d97f216cfc0684d89605e40e696e661acd7dfa50c071ce1ad1bbeaa3a16424e9b4b2bf05ef5d77fbb6
7
- data.tar.gz: dc34a8f3d8953b05bfddd57850236eefabdb503bee884978da04c74b9146848064710fb8290f46d4ccf11bd55bcfb95dd08b32aa97576f21feeb9f04f79ddc64
6
+ metadata.gz: 178862be03081097dce0c56b342e6815b4bb42918aafefe2b3ca407fb16d269aff49b79db0147003a6608149097eb030a693bfb3806cde467726676baa6f286a
7
+ data.tar.gz: 1f3cecc0b993ba3e8d017935f03165197ab88414bbf82be4c7601f73ede698df8f7e9f69761b6d412de70f82bd58be7542828ea21d0e26f330f598a90689381e
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2026-10-13
11
+
12
+ ### Added
13
+
14
+ - `assert_hash_attributes(hash, **expected)` assertion, applying the same comparisons to hash values
15
+ - Keys are looked up as given, then as strings, so symbol keys match parsed JSON
16
+ - A missing key fails, even when the expected value is `nil`
17
+
10
18
  ## [0.1.0] - 2026-09-24
11
19
 
12
20
  ### Added
data/README.md CHANGED
@@ -27,7 +27,7 @@ Then run:
27
27
  bundle install
28
28
  ```
29
29
 
30
- Requiring the gem mixes `assert_attributes` into `Minitest::Assertions`, so it is available in every `Minitest::Test`, `ActiveSupport::TestCase`, and integration test. Bundler requires it for you in a Rails app; otherwise add `require "minitest/attributes"` to your test helper.
30
+ Requiring the gem mixes `assert_attributes` and `assert_hash_attributes` into `Minitest::Assertions`, so it is available in every `Minitest::Test`, `ActiveSupport::TestCase`, and integration test. Bundler requires it for you in a Rails app; otherwise add `require "minitest/attributes"` to your test helper.
31
31
 
32
32
  ## Usage
33
33
 
@@ -44,6 +44,25 @@ A mismatch fails with a message such as:
44
44
  Expected Person#last_name to be "Bubblegum", but was "Abadeer"
45
45
  ```
46
46
 
47
+ ### Hashes
48
+
49
+ `assert_hash_attributes` makes the same comparisons against the values of a hash. Each key is looked up as given and then as a string, so symbol keys also match parsed JSON:
50
+
51
+ ```ruby
52
+ assert_hash_attributes(
53
+ JSON.parse(response.body),
54
+ "@type": "Person",
55
+ name: "Marceline",
56
+ nickname: nil
57
+ )
58
+ ```
59
+
60
+ A missing key fails with the hash's keys, even when the expected value is `nil`:
61
+
62
+ ```
63
+ Expected hash to have key :nickname, but its keys were ["@type", "name"]
64
+ ```
65
+
47
66
  ## Development
48
67
 
49
68
  After checking out the repo, run `bin/setup` to install dependencies. Then run `bundle exec rake` to run the tests and RuboCop. You can also run `bin/console` for an interactive prompt.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Minitest
4
4
  module Attributes
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
@@ -14,52 +14,81 @@ module Minitest
14
14
  # compared within +TIME_DELTA+ seconds, and an actual value that responds to
15
15
  # +to_plain_text+ (such as an Action Text rich text) is compared as plain
16
16
  # text. Everything else falls through to +assert_equal+.
17
+ #
18
+ # +assert_hash_attributes+ applies the same comparisons to the values of a
19
+ # hash.
17
20
  module Attributes
18
21
  TIME_DELTA = 1
19
22
 
20
23
  def assert_attributes(record, **expected_attributes)
21
24
  expected_attributes.each do |attribute, expected_value|
22
- assert_attribute(record, attribute, expected_value)
25
+ assert_value(
26
+ "#{record.class.name}##{attribute}",
27
+ expected_value,
28
+ record.public_send(attribute)
29
+ )
30
+ end
31
+ end
32
+
33
+ # Like +assert_attributes+, but reads each key from a hash. A key is looked
34
+ # up as given, then as a string, so symbol keys also match the string keys
35
+ # of parsed JSON:
36
+ #
37
+ # assert_hash_attributes(JSON.parse(body), "@type": "Person", age: 12)
38
+ #
39
+ # A missing key fails, even when the expected value is +nil+.
40
+ def assert_hash_attributes(hash, **expected_attributes)
41
+ expected_attributes.each do |key, expected_value|
42
+ assert_hash_attribute(hash, key, expected_value)
23
43
  end
24
44
  end
25
45
 
26
46
  private
27
47
 
28
- def assert_attribute(record, attribute, expected_value)
29
- actual_value = record.public_send(attribute)
48
+ def assert_hash_attribute(hash, key, expected_value)
49
+ found_key = [key, key.to_s].find { |candidate| hash.key?(candidate) }
50
+ assert(
51
+ found_key,
52
+ "Expected hash to have key #{key.inspect}, " \
53
+ "but its keys were #{hash.keys.inspect}"
54
+ )
55
+
56
+ assert_value(
57
+ "hash[#{found_key.inspect}]", expected_value, hash[found_key]
58
+ )
59
+ end
30
60
 
61
+ def assert_value(label, expected_value, actual_value)
31
62
  if expected_value.nil?
32
63
  assert_nil(
33
64
  actual_value,
34
- attribute_message(record, attribute, expected_value, actual_value)
65
+ value_message(label, expected_value, actual_value)
35
66
  )
36
67
  elsif expected_value.is_a?(Time)
37
68
  assert_in_delta(
38
69
  expected_value.to_f,
39
70
  actual_value.to_f,
40
71
  TIME_DELTA,
41
- attribute_message(record, attribute, expected_value, actual_value)
72
+ value_message(label, expected_value, actual_value)
42
73
  )
43
74
  elsif actual_value.respond_to?(:to_plain_text)
44
75
  plain_actual_value = actual_value.to_plain_text
45
76
  assert_equal(
46
77
  expected_value,
47
78
  plain_actual_value,
48
- attribute_message(
49
- record, attribute, expected_value, plain_actual_value
50
- )
79
+ value_message(label, expected_value, plain_actual_value)
51
80
  )
52
81
  else
53
82
  assert_equal(
54
83
  expected_value,
55
84
  actual_value,
56
- attribute_message(record, attribute, expected_value, actual_value)
85
+ value_message(label, expected_value, actual_value)
57
86
  )
58
87
  end
59
88
  end
60
89
 
61
- def attribute_message(record, attribute, expected_value, actual_value)
62
- "Expected #{record.class.name}##{attribute} to be " \
90
+ def value_message(label, expected_value, actual_value)
91
+ "Expected #{label} to be " \
63
92
  "#{expected_value.inspect}, but was #{actual_value.inspect}"
64
93
  end
65
94
  end
@@ -4,10 +4,12 @@ module Minitest
4
4
  TIME_DELTA: Integer
5
5
 
6
6
  def assert_attributes: (untyped record, **untyped expected_attributes) -> void
7
+ def assert_hash_attributes: (Hash[untyped, untyped] hash, **untyped expected_attributes) -> void
7
8
 
8
9
  private
9
10
 
10
- def assert_attribute: (untyped record, Symbol attribute, untyped expected_value) -> void
11
- def attribute_message: (untyped record, Symbol attribute, untyped expected_value, untyped actual_value) -> String
11
+ def assert_hash_attribute: (Hash[untyped, untyped] hash, Symbol key, untyped expected_value) -> void
12
+ def assert_value: (String label, untyped expected_value, untyped actual_value) -> void
13
+ def value_message: (String label, untyped expected_value, untyped actual_value) -> String
12
14
  end
13
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdullah Hashim