rematch 3.2.2 → 4.0.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: 517a212dcc929a169a02fb05526206e64ee3aa4f9a9dced33a76d0c0bca20698
4
- data.tar.gz: e1764805c826d287daf49ec747551e86a8736ba2cc572e5a3d7b7eea9fe3d923
3
+ metadata.gz: 18b629b32aa8af9d7c9218946f7467630f68e639930942b44a94f5bea4c77f8a
4
+ data.tar.gz: a49dbb4d655e006ab36147a0b94b6b6d125c436f148e2d4dcf876a621ec6f274
5
5
  SHA512:
6
- metadata.gz: b6ab2b85043428cd063a52ceaf93bd5e5a05a73d8d795946bdfdffecffdb19e7c4b545ea076cc633e87038947074d657574ebe0914fd254eff633c770a8444a6
7
- data.tar.gz: 38a7dd07e06f54900417e7a8344a34777a018380c157342f741f3b956bbb3bbcc24b900692dd9f096437fa7d75df55de0de8fe904c44bc7cd0249a96f56a36db
6
+ metadata.gz: 8c80817ea424ed8be19329fb01bb6d13a027eedf6aa5e3d20175fec32b5e6413eb4fb311f1fbae0c7fbe64a28f0ed90a00b2ab45199d064ac703d67f2af25dad
7
+ data.tar.gz: e2fbe2c78ae7c19f06412256485b14f4511f0c790586943c31aa6cf3a2a1bff7d7da66d1406470069645490a6af0ef89a870896c34fcca02f19774cf815ec509
@@ -22,28 +22,27 @@ module Minitest
22
22
  # Create the rematch object for each test
23
23
  def after_setup
24
24
  super
25
- @rematch = Rematch.new(path: method(name).source_location.first,
26
- id: "#{self.class.name}##{name}")
25
+ @rematch = Rematch.new(self)
27
26
  end
28
27
  end
29
28
 
30
29
  # Reopen the minitest module
31
30
  module Assertions
32
31
  # Main assertion
33
- def assert_rematch(key, actual, *args)
32
+ def assert_rematch(actual, *args)
34
33
  assertion = :assert_equal
35
34
  message = nil
36
35
  args.each { |arg| arg.is_a?(Symbol) ? assertion = arg : message = arg }
37
36
  if actual.nil? # use specific assert_nil after deprecation of assert_equal nil
38
- assert_nil @rematch.rematch(key, actual), message
37
+ assert_nil @rematch.rematch(actual), message
39
38
  else
40
- send assertion, @rematch.rematch(key, actual), actual, message # assert that the stored value is the same actual value
39
+ send assertion, @rematch.rematch(actual), actual, message # assert that the stored value is the same actual value
41
40
  end
42
41
  end
43
42
 
44
43
  # Temporarily used to store the actual value, useful for reconciliation of expected changed values
45
- def store_assert_rematch(key, actual, *_args)
46
- @rematch.rematch(key, actual, overwrite: true)
44
+ def store_assert_rematch(actual, *_args)
45
+ @rematch.rematch(actual, overwrite: true)
47
46
  # Always fail after storing, forcing the restore of the original assertion/expectation
48
47
  raise Minitest::Assertion, '[rematch] the value has been stored: remove the "store_" prefix to pass the test'
49
48
  end
@@ -51,7 +50,9 @@ module Minitest
51
50
 
52
51
  # Register expectations only if minitest/spec is loaded; ensure the right class in 6.0 and < 6.0
53
52
  if (expectation_class = defined?(Spec) && (defined?(Expectation) ? Expectation : Expectations))
54
- expectation_class.infect_an_assertion :assert_rematch, :must_rematch
55
- expectation_class.infect_an_assertion :store_assert_rematch, :store_must_rematch
53
+ expectation_class.infect_an_assertion :assert_rematch, :must_rematch, :reverse
54
+ expectation_class.alias_method :to_rematch, :must_rematch # to use with expect().to_rematch
55
+ expectation_class.infect_an_assertion :store_assert_rematch, :store_must_rematch, :reverse
56
+ expectation_class.alias_method :store_to_rematch, :store_must_rematch # to use with expect().store_to_rematch
56
57
  end
57
58
  end
data/lib/rematch.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fileutils'
4
+ require 'digest/sha1'
4
5
  require_relative 'rematch/store'
5
6
 
6
7
  # Handles the key/value store for each test
7
8
  class Rematch
8
- VERSION = '3.2.2'
9
+ VERSION = '4.0.0'
9
10
  CONFIG = { ext: '.yaml' } # rubocop:disable Style/MutableConstant
10
11
 
11
12
  @rebuild = false # rebuild the store?
@@ -26,35 +27,70 @@ class Rematch
26
27
  end
27
28
 
28
29
  # Instantiated at each test, stores the path and the unique id of the test being run
29
- def initialize(path:, id:)
30
- store_path = "#{path}#{CONFIG[:ext]}"
30
+ def initialize(test)
31
+ @path = test.method(test.name).source_location.first
32
+ store_path = "#{@path}#{CONFIG[:ext]}"
31
33
  self.class.check_rebuild(store_path)
32
- @store = Store.new(store_path, true)
33
- @id = id.tr('#: ', '_') # easier key string for clumsy yaml parsers/highlighters
34
+ @store = Store.new(store_path, true)
35
+ @id = test_uid(test.class.name, test.name)
34
36
  end
35
37
 
36
38
  # Retrieve the stored value for the current assertion if its key is known; store the value otherwise
37
- def rematch(key, value, overwrite: nil)
38
- # key = assertion_key(key)
39
+ def rematch(value, overwrite: nil)
40
+ key = assertion_key
39
41
  @store.transaction do |s|
40
- if s.root?(@id) # there is the root id
41
- if s[@id].key?(key) && !overwrite # there is the key and not overwrite
42
- s[@id][key] # return it
43
- else # not such a key
44
- s[@id][key] = value # set it
45
- store_warning(key) unless overwrite
46
- value
47
- end
48
- else # there is no root yet
49
- s[@id] = { key => value } # the key is the first one
50
- store_warning(key)
51
- value # always return the value
42
+ if s.root?(key) && !overwrite # there is the key and not overwrite
43
+ s[key] # return it
44
+ else # no such key or overwrite
45
+ s[key] = value # set it
46
+ tidy_store(s) # sort keys and cleanup orphans
47
+ store_warning(key) unless overwrite
48
+ value
52
49
  end
53
50
  end
54
51
  end
55
52
 
56
53
  def store_warning(key)
57
- warn "Rematch stored new value for: #{key.inspect}\n#{@id}\n#{@store.path}\n\n" \
58
- unless Rematch.skip_warning
54
+ warn "Rematch stored new value for: #{key.inspect}\n#{@store.path}\n\n" \
55
+ unless Rematch.skip_warning
56
+ end
57
+
58
+ protected
59
+
60
+ # Generate the unique id for the test (SHA1)
61
+ def test_uid(class_name, method_name)
62
+ Digest::SHA1.hexdigest("#{class_name}#{method_name}")
63
+ end
64
+
65
+ private
66
+
67
+ # Generate the key based on the line number and test ID
68
+ def assertion_key
69
+ line = caller_locations.find { |l| l.path == @path }&.lineno
70
+ "L#{line} #{@id}"
71
+ end
72
+
73
+ # Ensure the keys are sorted by the order of the tests in the file
74
+ # and remove keys that do not match any existing test (orphans)
75
+ def tidy_store(store)
76
+ # Optimization: only if Minitest is loaded
77
+ return unless defined?(Minitest::Runnable)
78
+
79
+ # Get all valid SHA1s from all runnables in this file
80
+ valid_ids = []
81
+ Minitest::Runnable.runnables.each do |runnable|
82
+ runnable.runnable_methods.each do |method_name|
83
+ file, = runnable.instance_method(method_name).source_location
84
+ next unless file == @path # @path is the test file path
85
+
86
+ valid_ids << test_uid(runnable.name, method_name)
87
+ end
88
+ end
89
+ # Extract all data
90
+ data = store.roots.to_h { |key| [key, store.delete(key)] }
91
+ # Re-add data in the correct order, filter orphans and sort
92
+ data.select { |key, _| valid_ids.include?(key.split.last) }
93
+ .sort_by { |key, _| key[/L(\d+)/, 1].to_i }
94
+ .each { |key, value| store[key] = value }
59
95
  end
60
96
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rematch
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
@@ -37,9 +37,9 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0'
40
- description: Instead of copying and pasting large outputs or big ruby structures into
41
- all the affected test files every time your code change, you can do it the easy
42
- way, possibly saving many hours of boring maintenance work!
40
+ description: Rematch declutters your tests by storing large outputs or structures
41
+ in separate files. It verifies them automatically and enables easy updates when
42
+ your code changes, eliminating tedious copy-paste maintenance.
43
43
  email:
44
44
  - dd.nexus@gmail.com
45
45
  executables: []
@@ -74,6 +74,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
74
  requirements: []
75
75
  rubygems_version: 3.6.9
76
76
  specification_version: 4
77
- summary: Declutter your test files from large hardcoded data and update them automatically
78
- when your code changes
77
+ summary: Declutter your test files and automatically update expected values.
79
78
  test_files: []