as_deprecation_tracker 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b25a9c470b3310b7a3112d290e0655811ea93c3d
4
+ data.tar.gz: 78857eba82e956ad61ad8e6276128fe4a73d6056
5
+ SHA512:
6
+ metadata.gz: 83efcef8a382e9c9cace6a2e942f7d96032d587b76b1ab36707cf3f7c37c82a1e6a8a241c1bdd8da5de298fe6e5ec2b2f705414f8c47208d3581059087629e0e
7
+ data.tar.gz: c6558bacefd24acba76e6aa3e6bb23beff1e26cf1ec502cc010f6172f7cdd07f86affaf919509eef9b58015fb2ab7d3e761b129b16800765684a422b9aa7b94d
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Dominic Cleal
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # as_deprecation_tracker
2
+
3
+ Tracks known ActiveSupport (Rails) deprecation warnings and catches new issues
4
+ when an unknown warning is seen.
5
+
6
+ This allows for easier upgrades of Rails and other AS-based apps because as
7
+ each deprecation warning is fixed, it's removed from the whitelist and any
8
+ attempt to reintroduce the deprecated call will fail. It's also useful when the
9
+ app runs on multiple versions of Rails and newer deprecation warnings can't be
10
+ fixed yet without breaking the older version.
11
+
12
+ The library maintains the whitelist in a configuration file that's usually
13
+ initially written by running the app test suite with an environment variable
14
+ set. When the tests are run normally, deprecation warnings triggered that
15
+ aren't in the config file will raise an exception. The call can then be fixed
16
+ or added to the whitelist with the provided instructions.
17
+
18
+ If you'd prefer just to fix all deprecation warnings at once then this gem is
19
+ unnecessary! Just use:
20
+
21
+ ```ruby
22
+ ActiveSupport::Deprecation.behavior = :raise
23
+ ```
24
+
25
+ in your test environment config.
26
+
27
+ ## Installation
28
+
29
+ $ gem install as_deprecation_tracker
30
+
31
+ or in your Gemfile:
32
+
33
+ gem 'as_deprecation_tracker', '~> 1.0', group: 'test'
34
+
35
+ This gem and its API is versioned according to semver.
36
+
37
+ It's recommended to only add the gem to the test Bundler group as raising
38
+ errors in production and development isn't desirable.
39
+
40
+ ## Usage
41
+
42
+ ### Automatic whitelisting
43
+
44
+ To set up an initial whitelist, run:
45
+
46
+ AS_DEPRECATION_RECORD=yes bin/rake test
47
+
48
+ This will generate `config/as_deprecation_whitelist.yaml` with a list of
49
+ specific instances of deprecated calls which can be committed. Subsequent `rake
50
+ test` runs will then automatically raise errors for new occurrences.
51
+
52
+ Re-run tests with `AS_DEPRECATION_RECORD=yes` to append new instances to the
53
+ existing configuration file, if you wish to whitelist rather than fix them.
54
+
55
+ ### Whitelist configuration
56
+
57
+ The whitelist may be broad, permitting any call causing a particular
58
+ deprecation message or be precise, only permitting known calls identified by
59
+ their backtrace. With broad whitelists, more instances of the same deprecated
60
+ call may be added, but precise whitelists require more maintenance if code is
61
+ moved and the backtrace changes.
62
+
63
+ The whitelist is stored in the Rails root at
64
+ `config/as_deprecation_whitelist.yaml` and is a YAML file containing a single
65
+ array of hashes:
66
+
67
+ ```yaml
68
+ ---
69
+ - message: "Deprecated call to X, use Y instead"
70
+ - message: "Deprecated call to Z"
71
+ callstack: "app/models/foo.rb:23:in `example_method'"
72
+ ```
73
+
74
+ Accepted keys are `message`, matching the exact deprecation message and
75
+ `callstack`, a string or an array forming the backtrace of the deprecation.
76
+ If an array is given for the callstack, all entries must match the caller.
77
+
78
+ The callstack will match on as much data as is provided - if only a file is
79
+ given, any matching deprecation within the file will be whitelisted. The line
80
+ number and method specification may be given for more specificity. The line
81
+ number may vary by up to ten lines from the recorded number by default (see
82
+ `line_tolerance` to tune). Usually the filename and method name are sufficient
83
+ to match the caller without needing line numbers.
84
+
85
+ ### Configuration
86
+
87
+ Use an initializer to change ASDT's behaviour at startup:
88
+
89
+ ```ruby
90
+ ASDeprecationTracker.config.envs = %w(test development)
91
+ ```
92
+
93
+ Supported options:
94
+
95
+ * `envs` is an array of string Rails environment names that ASDT will monitor
96
+ and raise errors for unpermitted deprecation warnings (defaults to
97
+ `['test']`)
98
+ * `line_tolerance` is the number of lines that callstack line numbers may
99
+ differ from the deprecated call (defaults to 10)
100
+ * `register_behavior` controls whether to change the AS::Deprecation behavior
101
+ to ASDeprecationTracker::Receiver at startup, may be disabled to use multiple
102
+ behaviors (defaults to true)
103
+ * `whitelist_file` to customise the location of the whitelist YAML file
104
+ (defaults to `config/as_deprecation_whitelist.yaml` beneath the Rails root)
105
+
106
+ ## License
107
+
108
+ Copyright (c) 2016 Dominic Cleal. Distributed under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+ require 'rubocop/rake_task'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/*_test.rb']
9
+ t.verbose = true
10
+ end
11
+
12
+ RuboCop::RakeTask.new
13
+
14
+ task default: %w(rubocop test)
data/config.ru ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'rubygems'
3
+ require 'bundler'
4
+
5
+ Bundler.require :default, :development
6
+
7
+ Combustion.initialize! :all
8
+ run Combustion::Application
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module ASDeprecationTracker
3
+ # Maintains configuration for one instance (usually global)
4
+ class Configuration
5
+ attr_accessor :envs, :line_tolerance, :register_behavior, :whitelist_file
6
+ alias register_behavior? register_behavior
7
+
8
+ def initialize
9
+ @envs = %w(test)
10
+ @line_tolerance = 10
11
+ @register_behavior = true
12
+ @whitelist_file = File.join(Rails.root, 'config', 'as_deprecation_whitelist.yaml')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require 'as_deprecation_tracker/receiver'
3
+
4
+ module ASDeprecationTracker
5
+ # Railtie to register for deprecation notifications
6
+ class Railtie < ::Rails::Railtie
7
+ initializer 'as_deprecation_tracker.deprecation_notifications', after: :load_environment_config, if: -> { ASDeprecationTracker.active? } do
8
+ Receiver.attach_to :rails
9
+ ActiveSupport::Deprecation.behavior = :notify if ASDeprecationTracker.config.register_behavior?
10
+
11
+ whitelist = ASDeprecationTracker.config.whitelist_file
12
+ ASDeprecationTracker.whitelist.load_file(whitelist) if File.exist?(whitelist)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/subscriber'
3
+ require 'as_deprecation_tracker/writer'
4
+
5
+ module ASDeprecationTracker
6
+ # Receives deprecation.rails events via ActiveSupport::Notifications
7
+ class Receiver < ::ActiveSupport::Subscriber
8
+ def deprecation(event)
9
+ return if ASDeprecationTracker.whitelist.matches?(event.payload)
10
+
11
+ message = event.payload[:message]
12
+ callstack = event.payload[:callstack].map(&:to_s)
13
+ if ENV['AS_DEPRECATION_RECORD'].present?
14
+ write_deprecation(message, callstack)
15
+ else
16
+ raise_deprecation(message, callstack)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def write_deprecation(message, callstack)
23
+ writer = ASDeprecationTracker::Writer.new(ASDeprecationTracker.config.whitelist_file)
24
+ writer.add(message, callstack)
25
+ writer.write_file
26
+ end
27
+
28
+ def raise_deprecation(message, callstack)
29
+ e = ActiveSupport::DeprecationException.new(message)
30
+ e.set_backtrace(callstack)
31
+ raise e
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module ASDeprecationTracker
3
+ VERSION = '1.0.0'.freeze
4
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'as_deprecation_tracker/whitelist_entry'
3
+
4
+ module ASDeprecationTracker
5
+ # Stores a list of known and ignored deprecation warnings, and provides a
6
+ # query interface to check if a warning matches the list
7
+ class Whitelist
8
+ attr_reader :list
9
+
10
+ def initialize
11
+ @list = []
12
+ end
13
+
14
+ def add_to_list(entries)
15
+ entries.each { |entry| @list << WhitelistEntry.new(entry) }
16
+ end
17
+
18
+ def clear
19
+ @list.clear
20
+ end
21
+
22
+ def load_file(path)
23
+ add_to_list(YAML.load(File.read(path)))
24
+ end
25
+
26
+ def matches?(deprecation)
27
+ @list.any? { |entry| entry.matches?(deprecation) }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ module ASDeprecationTracker
3
+ # Configuration of a whitelisted (known) deprecation warning matched by data
4
+ # such as a message and/or callstack
5
+ class WhitelistEntry
6
+ MESSAGE_CLEANUP_RE = Regexp.new('\ADEPRECATION WARNING: (.+) \(called from.*')
7
+ CALLSTACK_FILE_RE = Regexp.new('\A(.*?)(?::(\d+))?(?::in `(.+)\')?\z')
8
+
9
+ def initialize(entry)
10
+ entry = entry.with_indifferent_access
11
+ raise('Missing `message` or `callstack` from whitelist entry') unless entry.key?(:message) || entry.key?(:callstack)
12
+ @message = entry[:message]
13
+ @callstack = callstack_to_files_lines(Array.wrap(entry[:callstack]))
14
+ end
15
+
16
+ def matches?(deprecation)
17
+ return false if @message.present? && !message_matches?(deprecation[:message])
18
+ return false if @callstack.present? && !callstack_matches?(deprecation[:callstack])
19
+ true
20
+ end
21
+
22
+ private
23
+
24
+ def message_matches?(message)
25
+ cleanup_match = MESSAGE_CLEANUP_RE.match(message)
26
+ message = cleanup_match[1] if cleanup_match
27
+ message == @message
28
+ end
29
+
30
+ def callstack_to_files_lines(callstack)
31
+ callstack.map do |entry|
32
+ file_match = CALLSTACK_FILE_RE.match(entry)
33
+ [file_match[1], file_match[2].nil? ? nil : file_match[2].to_i, file_match[3]]
34
+ end
35
+ end
36
+
37
+ def callstack_matches?(callstack)
38
+ callstack = callstack_to_files_lines(callstack)
39
+
40
+ @callstack.all? do |whitelist_entry|
41
+ callstack_entry_matches?(whitelist_entry, callstack)
42
+ end
43
+ end
44
+
45
+ def callstack_entry_matches?(whitelist_entry, callstack)
46
+ callstack.any? do |callstack_entry|
47
+ callstack_entry[0] == whitelist_entry[0] &&
48
+ line_number_within_tolerance(callstack_entry[1], whitelist_entry[1]) &&
49
+ method_name_matches(callstack_entry[2], whitelist_entry[2])
50
+ end
51
+ end
52
+
53
+ def line_number_within_tolerance(line1, line2)
54
+ return true if line1.nil? || line2.nil?
55
+ (line1 - line2).abs <= ASDeprecationTracker.config.line_tolerance
56
+ end
57
+
58
+ def method_name_matches(method1, method2)
59
+ return true if method1.nil? || method2.nil?
60
+ method1 == method2
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ require 'as_deprecation_tracker/whitelist_entry'
3
+ require 'rails/backtrace_cleaner'
4
+
5
+ module ASDeprecationTracker
6
+ # Rewrites the whitelist configuration file to append new observed entries
7
+ class Writer
8
+ def initialize(filename)
9
+ @filename = filename
10
+ @contents = []
11
+ @contents = YAML.load(File.read(filename)) || [] if File.exist?(filename)
12
+ end
13
+
14
+ def add(message, callstack)
15
+ cleanup_match = WhitelistEntry::MESSAGE_CLEANUP_RE.match(message)
16
+ message = cleanup_match[1] if cleanup_match
17
+
18
+ callstack = Rails::BacktraceCleaner.new.clean(callstack, :silent)
19
+
20
+ @contents << { 'message' => message, 'callstack' => callstack.first }
21
+ end
22
+
23
+ def contents
24
+ @contents.sort_by { |e| e.values_at('message', 'callstack') }.to_yaml
25
+ end
26
+
27
+ def write_file
28
+ File.write(@filename, contents)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # Entry point, provides constant with access to global configuration only
3
+ module ASDeprecationTracker
4
+ require 'as_deprecation_tracker/configuration'
5
+ require 'as_deprecation_tracker/railtie'
6
+ require 'as_deprecation_tracker/version'
7
+ require 'as_deprecation_tracker/whitelist'
8
+
9
+ def self.active?
10
+ config.envs.include?(Rails.env)
11
+ end
12
+
13
+ def self.config
14
+ @config ||= Configuration.new
15
+ end
16
+
17
+ def self.whitelist
18
+ @whitelist ||= Whitelist.new
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class ASDeprecationTrackerTest < ASDeprecationTracker::TestCase
5
+ def test_active?
6
+ assert ASDeprecationTracker.active?
7
+ end
8
+
9
+ def test_active_in_other_env
10
+ ASDeprecationTracker.expects(:config).twice.returns(ASDeprecationTracker::Configuration.new)
11
+ ASDeprecationTracker.config.envs = ['development']
12
+ refute ASDeprecationTracker.active?
13
+ end
14
+
15
+ def test_config
16
+ assert_kind_of ASDeprecationTracker::Configuration, ASDeprecationTracker.config
17
+ end
18
+
19
+ def test_config_returns_same_configuration
20
+ config = ASDeprecationTracker.config
21
+ assert_equal config, ASDeprecationTracker.config
22
+ end
23
+
24
+ def test_whitelist
25
+ assert_kind_of ASDeprecationTracker::Whitelist, ASDeprecationTracker.whitelist
26
+ end
27
+
28
+ def test_whitelist_returns_same_whitelist
29
+ whitelist = ASDeprecationTracker.whitelist
30
+ assert_equal whitelist, ASDeprecationTracker.whitelist
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class ConfigurationTest < ASDeprecationTracker::TestCase
5
+ def setup
6
+ @config = ASDeprecationTracker::Configuration.new
7
+ super
8
+ end
9
+
10
+ def test_envs
11
+ assert_equal ['test'], @config.envs
12
+ end
13
+
14
+ def test_envs=
15
+ @config.envs = ['development']
16
+ assert_equal ['development'], @config.envs
17
+ end
18
+
19
+ def test_line_tolerance
20
+ assert_equal 10, @config.line_tolerance
21
+ end
22
+
23
+ def test_line_tolerance=
24
+ @config.line_tolerance = 42
25
+ assert_equal 42, @config.line_tolerance
26
+ end
27
+
28
+ def test_register_behavior?
29
+ assert_equal true, @config.register_behavior?
30
+ end
31
+
32
+ def test_register_behavior=
33
+ @config.register_behavior = false
34
+ assert_equal false, @config.register_behavior?
35
+ end
36
+
37
+ def test_whitelist_file
38
+ assert_kind_of String, @config.whitelist_file
39
+ assert File.exist?(@config.whitelist_file)
40
+ end
41
+
42
+ def test_whitelist_file=
43
+ @config.whitelist_file = 'another_file.yaml'
44
+ assert_equal 'another_file.yaml', @config.whitelist_file
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ Rails.application.routes.draw do
3
+ #
4
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class RailtieTest < ASDeprecationTracker::TestCase
5
+ def test_deprecation_behavior
6
+ assert_equal [ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:notify]], ActiveSupport::Deprecation.behavior
7
+ end
8
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class ReceiverTest < ASDeprecationTracker::TestCase
5
+ def test_deprecation_whitelisted
6
+ whitelist = ASDeprecationTracker::Whitelist.new
7
+ ASDeprecationTracker.expects(:whitelist).returns(whitelist)
8
+ stack = caller
9
+ whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(true)
10
+ ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
11
+ end
12
+
13
+ def test_deprecation_unknown
14
+ whitelist = ASDeprecationTracker::Whitelist.new
15
+ ASDeprecationTracker.expects(:whitelist).returns(whitelist)
16
+ stack = caller
17
+ whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(false)
18
+ e = assert_raises(ActiveSupport::DeprecationException) do
19
+ ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
20
+ end
21
+ assert_equal 'deprecated call', e.message
22
+ assert_equal stack, e.backtrace
23
+ end
24
+
25
+ def test_deprecation_unknown_record
26
+ whitelist = ASDeprecationTracker::Whitelist.new
27
+ ASDeprecationTracker.expects(:whitelist).returns(whitelist)
28
+ stack = caller
29
+ whitelist.expects(:matches?).with(message: 'deprecated call', callstack: stack).returns(false)
30
+ ASDeprecationTracker::Writer.any_instance.expects(:add).with('deprecated call', stack)
31
+ ASDeprecationTracker::Writer.any_instance.expects(:write_file)
32
+ ENV['AS_DEPRECATION_RECORD'] = 'true'
33
+ ASDeprecationTracker::Receiver.new.deprecation(event(message: 'deprecated call', callstack: stack))
34
+ ensure
35
+ ENV.delete('AS_DEPRECATION_RECORD')
36
+ end
37
+
38
+ def test_subscription
39
+ ASDeprecationTracker::Receiver.any_instance.expects(:deprecation)
40
+ ActiveSupport::Notifications.instrument('deprecation.rails', message: 'test')
41
+ end
42
+
43
+ private
44
+
45
+ def event(payload)
46
+ mock('event').tap do |event|
47
+ event.stubs(:payload).returns(payload)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ require 'minitest/autorun'
3
+ require 'mocha/mini_test'
4
+ require 'combustion'
5
+
6
+ require 'as_deprecation_tracker'
7
+
8
+ Combustion.path = 'test/internal'
9
+ Combustion.initialize!
10
+
11
+ module ASDeprecationTracker
12
+ class TestCase < ::Minitest::Test; end
13
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class WhitelistEntryTest < ASDeprecationTracker::TestCase
5
+ def test_initialize_with_strings
6
+ ASDeprecationTracker::WhitelistEntry.new('message' => 'test')
7
+ end
8
+
9
+ def test_initialize_with_symbols
10
+ ASDeprecationTracker::WhitelistEntry.new(message: 'test')
11
+ end
12
+
13
+ def test_matches_message_and_callstack
14
+ assert entry.matches?(deprecation)
15
+ end
16
+
17
+ def test_matches_message_with_surrounding_content
18
+ assert entry.matches?(deprecation(message: 'DEPRECATION WARNING: uniq is deprecated and will be removed (called from block in <class:Foo> at app/models/foo.rb:23)'))
19
+ end
20
+
21
+ def test_matches_message_only
22
+ assert entry(callstack: nil).matches?(deprecation(callstack: caller))
23
+ end
24
+
25
+ def test_matches_callstack_only
26
+ assert entry(message: nil).matches?(deprecation)
27
+ end
28
+
29
+ def test_matches_partial_callstack_top
30
+ assert entry(callstack: ['/home/user/app/models/foo.rb:23']).matches?(deprecation)
31
+ end
32
+
33
+ def test_matches_partial_callstack_bottom
34
+ assert entry(callstack: ['/home/user/app/controllers/foos_controller.rb:42']).matches?(deprecation)
35
+ end
36
+
37
+ def test_matches_partial_callstack_multiple
38
+ assert entry(callstack: [
39
+ '/home/user/app/models/foo.rb:23',
40
+ '/home/user/app/controllers/foos_controller.rb:42'
41
+ ]).matches?(deprecation)
42
+ end
43
+
44
+ def test_matches_partial_callstack_within_tolerance
45
+ assert entry(callstack: ['/home/user/app/models/foo.rb:25']).matches?(deprecation)
46
+ end
47
+
48
+ def test_matches_partial_callstack_outside_tolerance
49
+ refute entry(callstack: ['/home/user/app/models/foo.rb:34']).matches?(deprecation)
50
+ end
51
+
52
+ def test_matches_partial_callstack_same_method
53
+ assert entry(callstack: ['/home/user/app/models/foo.rb:in `example_method\'']).matches?(deprecation)
54
+ end
55
+
56
+ def test_matches_partial_callstack_different_method
57
+ refute entry(callstack: ['/home/user/app/models/foo.rb:23:in `another_method\'']).matches?(deprecation)
58
+ end
59
+
60
+ def test_matches_partial_callstack_different_method_no_line
61
+ refute entry(callstack: ['/home/user/app/models/foo.rb:in `another_method\'']).matches?(deprecation)
62
+ end
63
+
64
+ def test_matches_partial_callstack_within_tolerance_same_method
65
+ assert entry(callstack: ['/home/user/app/models/foo.rb:25:in `example_method\'']).matches?(deprecation)
66
+ end
67
+
68
+ def test_matches_partial_callstack_outside_tolerance_same_method
69
+ refute entry(callstack: ['/home/user/app/models/foo.rb:34:in `example_method\'']).matches?(deprecation)
70
+ end
71
+
72
+ def test_matches_partial_callstack_string
73
+ assert entry(callstack: '/home/user/app/models/foo.rb:23').matches?(deprecation)
74
+ end
75
+
76
+ def test_matches_partial_callstack_file
77
+ assert entry(callstack: ['/home/user/app/models/foo.rb']).matches?(deprecation)
78
+ end
79
+
80
+ def test_matches_different_message_same_callstack
81
+ refute entry.matches?(deprecation(message: 'a different method is deprecated'))
82
+ end
83
+
84
+ def test_matches_same_message_different_callstack
85
+ refute entry.matches?(deprecation(callstack: caller))
86
+ end
87
+
88
+ def test_matches_different_message_different_callstack
89
+ refute entry.matches?(deprecation(message: 'a different method is deprecated', callstack: caller))
90
+ end
91
+
92
+ private
93
+
94
+ def deprecation(overrides = {})
95
+ {
96
+ message: 'uniq is deprecated and will be removed',
97
+ callstack: [
98
+ '/home/user/app/models/foo.rb:23:in `example_method\'',
99
+ '/home/user/app/controllers/foos_controller.rb:42:in `update\'',
100
+ '/home/user/test/controllers/foos_controller_test.rb:18:in `block in <class:FoosControllerTest>\''
101
+ ]
102
+ }.merge(overrides).compact
103
+ end
104
+
105
+ def entry(overrides = {})
106
+ ASDeprecationTracker::WhitelistEntry.new(deprecation(overrides))
107
+ end
108
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class WhitelistTest < ASDeprecationTracker::TestCase
5
+ def setup
6
+ @whitelist = ASDeprecationTracker::Whitelist.new
7
+ super
8
+ end
9
+
10
+ def test_add_to_list
11
+ @whitelist.add_to_list([entry])
12
+ assert_equal 1, @whitelist.list.count
13
+ end
14
+
15
+ def test_clear
16
+ @whitelist.add_to_list([entry])
17
+ @whitelist.clear
18
+ assert @whitelist.list.empty?
19
+ end
20
+
21
+ def test_load_file
22
+ File.expects(:read).with('root/config/as_deprecation_whitelist.yaml').returns("---\n- :message: test\n")
23
+ @whitelist.load_file('root/config/as_deprecation_whitelist.yaml')
24
+ assert_equal 1, @whitelist.list.count
25
+ end
26
+
27
+ def test_matches_failure
28
+ @whitelist.add_to_list([entry])
29
+ deprecation = mock('deprecation')
30
+ @whitelist.list.first.expects(:matches?).with(deprecation).returns(false)
31
+ refute @whitelist.matches?(deprecation)
32
+ end
33
+
34
+ def test_matches_success
35
+ @whitelist.add_to_list([entry])
36
+ deprecation = mock('deprecation')
37
+ @whitelist.list.first.expects(:matches?).with(deprecation).returns(true)
38
+ assert @whitelist.matches?(deprecation)
39
+ end
40
+
41
+ private
42
+
43
+ def entry
44
+ { message: 'deprecated call', callstack: caller }
45
+ end
46
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class WriterTest < ASDeprecationTracker::TestCase
5
+ def test_add
6
+ writer = new_writer
7
+ writer.add('deprecated call', ['app/models/a.rb:23', 'app/models/b.rb:42'])
8
+ assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
9
+ end
10
+
11
+ def test_add_strips_surrounding
12
+ writer = new_writer
13
+ writer.add('DEPRECATION WARNING: deprecated call (called from app/models/a.rb:23)', ['app/models/a.rb:23', 'app/models/b.rb:42'])
14
+ assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
15
+ end
16
+
17
+ def test_add_cleans_callstack
18
+ writer = new_writer
19
+ Gem.expects(:path).returns(['/home/user/.rvm/gems/ruby-2.3.0'])
20
+ writer.add('deprecated call', ['/home/user/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.7.1/lib/active_record/relation/finder_methods.rb:280:in `exists?\'', 'app/models/a.rb:23', 'app/models/b.rb:42'])
21
+ assert_equal [{ 'message' => 'deprecated call', 'callstack' => 'app/models/a.rb:23' }], YAML.load(writer.contents)
22
+ end
23
+
24
+ def test_contents_new_file_is_array
25
+ assert_equal [], YAML.load(new_writer('').contents)
26
+ end
27
+
28
+ def test_contents_sorting
29
+ writer = new_writer
30
+ writer.add('deprecated call 1', ['app/models/a.rb:42', 'app/models/b.rb:42'])
31
+ writer.add('deprecated call 2', ['app/models/a.rb:23', 'app/models/b.rb:42'])
32
+ writer.add('deprecated call 1', ['app/models/a.rb:23', 'app/models/b.rb:42'])
33
+ assert_equal [
34
+ { 'message' => 'deprecated call 1', 'callstack' => 'app/models/a.rb:23' },
35
+ { 'message' => 'deprecated call 1', 'callstack' => 'app/models/a.rb:42' },
36
+ { 'message' => 'deprecated call 2', 'callstack' => 'app/models/a.rb:23' }
37
+ ], YAML.load(writer.contents)
38
+ end
39
+
40
+ def test_write_file
41
+ writer = new_writer
42
+ writer.expects(:contents).returns('--- []')
43
+ File.expects(:write).with('root/config/as_deprecation_whitelist.yaml', '--- []')
44
+ writer.write_file
45
+ end
46
+
47
+ private
48
+
49
+ def new_writer(input = '')
50
+ File.expects(:exist?).with('root/config/as_deprecation_whitelist.yaml').returns(true)
51
+ File.expects(:read).with('root/config/as_deprecation_whitelist.yaml').returns(input)
52
+ ASDeprecationTracker::Writer.new('root/config/as_deprecation_whitelist.yaml')
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: as_deprecation_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dominic Cleal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '4.2'
41
+ description: Tracks known ActiveSupport (Rails) deprecation warnings and catches new
42
+ issues when an unknown warning is seen.
43
+ email: dominic@cleal.org
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - config.ru
52
+ - lib/as_deprecation_tracker.rb
53
+ - lib/as_deprecation_tracker/configuration.rb
54
+ - lib/as_deprecation_tracker/railtie.rb
55
+ - lib/as_deprecation_tracker/receiver.rb
56
+ - lib/as_deprecation_tracker/version.rb
57
+ - lib/as_deprecation_tracker/whitelist.rb
58
+ - lib/as_deprecation_tracker/whitelist_entry.rb
59
+ - lib/as_deprecation_tracker/writer.rb
60
+ - test/as_deprecation_tracker_test.rb
61
+ - test/configuration_test.rb
62
+ - test/internal/config/as_deprecation_whitelist.yaml
63
+ - test/internal/config/routes.rb
64
+ - test/internal/log/.gitignore
65
+ - test/internal/public/favicon.ico
66
+ - test/railtie_test.rb
67
+ - test/receiver_test.rb
68
+ - test/test_helper.rb
69
+ - test/whitelist_entry_test.rb
70
+ - test/whitelist_test.rb
71
+ - test/writer_test.rb
72
+ homepage: https://github.com/domcleal/as_deprecation_tracker
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.0.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.6.8
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Track known ActiveSupport deprecation warnings
96
+ test_files: []