appmap 0.23.0 → 0.25.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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +17 -8
  4. data/.travis.yml +6 -0
  5. data/CHANGELOG.md +19 -0
  6. data/README.md +29 -12
  7. data/Rakefile +3 -3
  8. data/appmap.gemspec +3 -1
  9. data/exe/appmap +6 -18
  10. data/lib/appmap.rb +47 -6
  11. data/lib/appmap/algorithm/prune_class_map.rb +2 -0
  12. data/lib/appmap/algorithm/stats.rb +4 -2
  13. data/lib/appmap/class_map.rb +143 -0
  14. data/lib/appmap/command/record.rb +8 -6
  15. data/lib/appmap/command/stats.rb +2 -0
  16. data/lib/appmap/command/upload.rb +4 -2
  17. data/lib/appmap/event.rb +168 -0
  18. data/lib/appmap/hook.rb +151 -0
  19. data/lib/appmap/middleware/remote_recording.rb +14 -20
  20. data/lib/appmap/rails/action_handler.rb +10 -6
  21. data/lib/appmap/rails/sql_handler.rb +10 -8
  22. data/lib/appmap/railtie.rb +31 -18
  23. data/lib/appmap/rspec.rb +238 -261
  24. data/lib/appmap/trace.rb +88 -0
  25. data/lib/appmap/version.rb +1 -1
  26. data/package-lock.json +90 -92
  27. data/spec/abstract_controller4_base_spec.rb +1 -1
  28. data/spec/abstract_controller_base_spec.rb +7 -3
  29. data/spec/config_spec.rb +25 -0
  30. data/spec/fixtures/hook/attr_accessor.rb +5 -0
  31. data/spec/fixtures/hook/class_method.rb +17 -0
  32. data/spec/fixtures/hook/constructor.rb +7 -0
  33. data/spec/fixtures/hook/exception_method.rb +11 -0
  34. data/spec/fixtures/hook/instance_method.rb +23 -0
  35. data/spec/fixtures/rails4_users_app/app/controllers/api/users_controller.rb +3 -3
  36. data/spec/fixtures/rails4_users_app/config/database.yml +2 -1
  37. data/spec/fixtures/rails4_users_app/docker-compose.yml +2 -0
  38. data/spec/fixtures/rails_users_app/.ruby-version +1 -1
  39. data/spec/fixtures/rails_users_app/app/controllers/api/users_controller.rb +2 -2
  40. data/spec/fixtures/rails_users_app/config/database.yml +2 -1
  41. data/spec/fixtures/rails_users_app/create_app +1 -0
  42. data/spec/fixtures/rails_users_app/docker-compose.yml +4 -0
  43. data/spec/fixtures/rails_users_app/spec/models/user_spec.rb +1 -1
  44. data/spec/hook_spec.rb +357 -0
  45. data/spec/rails_spec_helper.rb +25 -16
  46. data/spec/railtie_spec.rb +1 -1
  47. data/spec/record_sql_rails_pg_spec.rb +1 -2
  48. data/spec/remote_recording_spec.rb +117 -0
  49. data/spec/spec_helper.rb +1 -0
  50. data/test/cli_test.rb +7 -36
  51. data/test/fixtures/cli_record_test/appmap.yml +2 -1
  52. data/test/fixtures/cli_record_test/lib/cli_record_test/main.rb +4 -2
  53. data/test/test_helper.rb +0 -42
  54. metadata +46 -62
  55. data/exe/_appmap-record-self +0 -49
  56. data/lib/appmap/command/inspect.rb +0 -14
  57. data/lib/appmap/config.rb +0 -65
  58. data/lib/appmap/config/directory.rb +0 -65
  59. data/lib/appmap/config/file.rb +0 -13
  60. data/lib/appmap/config/named_function.rb +0 -21
  61. data/lib/appmap/config/package_dir.rb +0 -52
  62. data/lib/appmap/config/path.rb +0 -25
  63. data/lib/appmap/feature.rb +0 -262
  64. data/lib/appmap/inspect.rb +0 -91
  65. data/lib/appmap/inspect/inspector.rb +0 -99
  66. data/lib/appmap/inspect/parse_node.rb +0 -170
  67. data/lib/appmap/inspect/parser.rb +0 -15
  68. data/lib/appmap/parser.rb +0 -60
  69. data/lib/appmap/rspec/parse_node.rb +0 -41
  70. data/lib/appmap/rspec/parser.rb +0 -15
  71. data/lib/appmap/trace/event_handler/rack_handler_webrick.rb +0 -65
  72. data/lib/appmap/trace/tracer.rb +0 -356
  73. data/spec/fixtures/rails_users_app/bin/_appmap-record-self +0 -29
  74. data/spec/rack_handler_webrick_spec.rb +0 -59
  75. data/test/config_test.rb +0 -149
  76. data/test/explict_inspect_test.rb +0 -29
  77. data/test/fixtures/active_record_like/active_record.rb +0 -2
  78. data/test/fixtures/active_record_like/active_record/aggregations.rb +0 -4
  79. data/test/fixtures/active_record_like/active_record/association.rb +0 -4
  80. data/test/fixtures/active_record_like/active_record/associations/join_dependency.rb +0 -6
  81. data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_base.rb +0 -8
  82. data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_part.rb +0 -8
  83. data/test/fixtures/active_record_like/active_record/caps/caps.rb +0 -4
  84. data/test/fixtures/ignore_non_ruby_file/class.rb +0 -3
  85. data/test/fixtures/ignore_non_ruby_file/non-ruby.txt +0 -1
  86. data/test/fixtures/includes_excludes/lib/a/a_1.rb +0 -6
  87. data/test/fixtures/includes_excludes/lib/a/a_2.rb +0 -6
  88. data/test/fixtures/includes_excludes/lib/a/x/x_1.rb +0 -8
  89. data/test/fixtures/includes_excludes/lib/b/b_1.rb +0 -6
  90. data/test/fixtures/includes_excludes/lib/root_1.rb +0 -4
  91. data/test/fixtures/inspect_multiple_subdirs/module_a.rb +0 -2
  92. data/test/fixtures/inspect_multiple_subdirs/module_a/class_a.rb +0 -5
  93. data/test/fixtures/inspect_multiple_subdirs/module_b.rb +0 -2
  94. data/test/fixtures/inspect_multiple_subdirs/module_b/class_b.rb +0 -5
  95. data/test/fixtures/inspect_multiple_subdirs/module_b/class_c.rb +0 -5
  96. data/test/fixtures/inspect_package/module_a/module_b/class_in_module.rb +0 -6
  97. data/test/fixtures/parse_file/defs_static_function.rb +0 -96
  98. data/test/fixtures/parse_file/function_within_class.rb +0 -36
  99. data/test/fixtures/parse_file/include_public_methods.rb +0 -127
  100. data/test/fixtures/parse_file/instance_function.rb +0 -17
  101. data/test/fixtures/parse_file/modules.rb +0 -71
  102. data/test/fixtures/parse_file/sclass_static_function.rb +0 -88
  103. data/test/fixtures/parse_file/toplevel_class.rb +0 -13
  104. data/test/fixtures/parse_file/toplevel_function.rb +0 -14
  105. data/test/fixtures/trace_test/trace_program_1.rb +0 -44
  106. data/test/implicit_inspect_test.rb +0 -33
  107. data/test/include_exclude_test.rb +0 -48
  108. data/test/prerecorded_trace_test.rb +0 -76
  109. data/test/trace_test.rb +0 -92
@@ -3,7 +3,7 @@ require 'rails_spec_helper'
3
3
  describe 'AbstractControllerBase' do
4
4
  before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
5
5
  include_context 'Rails app pg database'
6
-
6
+
7
7
  around(:each) do |example|
8
8
  FileUtils.rm_rf tmpdir
9
9
  FileUtils.mkdir_p tmpdir
@@ -17,7 +17,11 @@ describe 'AbstractControllerBase' do
17
17
  let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json') }
18
18
 
19
19
  describe 'testing with rspec' do
20
- it 'Message fields are recorded in the appmap' do
20
+ it 'inventory file is printed' do
21
+ expect(File).to exist(File.join(tmpdir, 'appmap/rspec/Inventory.appmap.json'))
22
+ end
23
+
24
+ it 'message fields are recorded in the appmap' do
21
25
  expect(File).to exist(appmap_json)
22
26
  appmap = JSON.parse(File.read(appmap_json)).to_yaml
23
27
 
@@ -50,7 +54,7 @@ describe 'AbstractControllerBase' do
50
54
  expect(appmap).to match(<<-CREATE_CALL.strip)
51
55
  event: call
52
56
  defined_class: Api::UsersController
53
- method_id: create_user
57
+ method_id: build_user
54
58
  path: app/controllers/api/users_controller.rb
55
59
  lineno: 23
56
60
  static: false
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_spec_helper'
4
+ require 'active_support/core_ext'
5
+ require 'appmap/hook'
6
+
7
+ describe AppMap::Hook::Config do
8
+ it 'loads from a Hash' do
9
+ config_data = {
10
+ name: 'test',
11
+ packages: [
12
+ {
13
+ path: 'path-1'
14
+ },
15
+ {
16
+ path: 'path-2',
17
+ exclude: [ 'exclude-1' ]
18
+ }
19
+ ]
20
+ }.deep_stringify_keys!
21
+ config = AppMap::Hook::Config.load(config_data)
22
+
23
+ expect(config.to_h.deep_stringify_keys!).to eq(config_data)
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AttrAccessor
4
+ attr_accessor :value
5
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ClassMethod
4
+ class << self
5
+ def say_default
6
+ 'default'
7
+ end
8
+ end
9
+
10
+ def ClassMethod.say_class_defined
11
+ 'defined with explicit class scope'
12
+ end
13
+
14
+ def self.say_self_defined
15
+ 'defined with self class scope'
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Constructor
4
+ def initialize(value)
5
+ @value = value
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ExceptionMethod
4
+ def to_s
5
+ 'Exception Method fixture'
6
+ end
7
+
8
+ def raise_exception
9
+ raise 'Exception occurred in raise_exception'
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class InstanceMethod
4
+ def to_s
5
+ 'Instance Method fixture'
6
+ end
7
+
8
+ def say_default
9
+ 'default'
10
+ end
11
+
12
+ def say_echo(arg)
13
+ arg.to_s
14
+ end
15
+
16
+ def say_kw(kw: 'kw')
17
+ kw.to_s
18
+ end
19
+
20
+ def say_block(&block)
21
+ yield
22
+ end
23
+ end
@@ -6,7 +6,7 @@ module Api
6
6
  end
7
7
 
8
8
  def create
9
- @user = create_user(params.slice(:login).to_unsafe_h)
9
+ @user = build_user(params.slice(:login).to_unsafe_h)
10
10
  unless @user.valid?
11
11
  error = {
12
12
  code: 'invalid',
@@ -18,9 +18,9 @@ module Api
18
18
  end
19
19
  @user.save
20
20
  render json: @user, status: :created
21
- end
21
+ end
22
22
 
23
- def create_user(params)
23
+ def build_user(params)
24
24
  User.new(params)
25
25
  end
26
26
  end
@@ -1,5 +1,6 @@
1
1
  default: &default
2
- host: pg
2
+ host: <%= ENV['PGHOST'] || 'pg' %>
3
+ port: <%= ENV['PGPORT'] || 5432 %>
3
4
  user: postgres
4
5
  adapter: postgresql
5
6
  encoding: unicode
@@ -6,6 +6,8 @@ services:
6
6
  dockerfile: Dockerfile.pg
7
7
  ports:
8
8
  - "5432"
9
+ environment:
10
+ POSTGRES_HOST_AUTH_METHOD: trust
9
11
 
10
12
  app:
11
13
  build:
@@ -1 +1 @@
1
- 2.5.5
1
+ 2.6.2
@@ -6,7 +6,7 @@ module Api
6
6
  end
7
7
 
8
8
  def create
9
- @user = create_user(params.slice(:login).to_unsafe_h)
9
+ @user = build_user(params.slice(:login).to_unsafe_h)
10
10
  unless @user.valid?
11
11
  error = {
12
12
  code: 'invalid',
@@ -20,7 +20,7 @@ module Api
20
20
  render json: @user, status: :created
21
21
  end
22
22
 
23
- def create_user(params)
23
+ def build_user(params)
24
24
  User.new(params)
25
25
  end
26
26
  end
@@ -1,5 +1,6 @@
1
1
  default: &default
2
- host: pg
2
+ host: <%= ENV['PGHOST'] || 'pg' %>
3
+ port: <%= ENV['PGPORT'] || 5432 %>
3
4
  user: postgres
4
5
  adapter: postgresql
5
6
  encoding: unicode
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bash
2
+ set -e
2
3
 
3
4
  # Just checking for a healthy container isn't enough, apparently. If
4
5
  # we don't wait here, sometimes the database is inaccessible.
@@ -6,6 +6,8 @@ services:
6
6
  dockerfile: Dockerfile.pg
7
7
  ports:
8
8
  - "5432"
9
+ environment:
10
+ POSTGRES_HOST_AUTH_METHOD: trust
9
11
 
10
12
  app:
11
13
  build:
@@ -16,6 +18,8 @@ services:
16
18
  [ "./bin/rails", "server", "-b", "0.0.0.0", "webrick" ]
17
19
  environment:
18
20
  RAILS_ENV:
21
+ ORM_MODULE:
22
+ APPMAP:
19
23
  volumes:
20
24
  - .:/src/app
21
25
  ports:
@@ -2,7 +2,7 @@ require 'rails_helper'
2
2
 
3
3
  describe User, feature_group: 'User', appmap: true do
4
4
  # TODO: appmap/rspec doesn't handle shared_examples_for 100% correctly yet.
5
- # In my tests, only one of these two tests will be emitted as an
5
+ # In my tests, only one of these two tests will be emitted as an appmap.
6
6
  shared_examples_for 'creates the user' do |username|
7
7
  let(:login) { username }
8
8
  let(:user) { User.new(login: login) }
data/spec/hook_spec.rb ADDED
@@ -0,0 +1,357 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_spec_helper'
4
+ require 'appmap/hook'
5
+ require 'appmap/event'
6
+ require 'diffy'
7
+
8
+ describe 'AppMap class Hooking' do
9
+ def collect_events(tracer)
10
+ [].tap do |events|
11
+ while tracer.event?
12
+ events << tracer.next_event.to_h
13
+ end
14
+ end.map do |event|
15
+ event.delete(:thread_id)
16
+ event.delete(:elapsed)
17
+ delete_object_id = ->(obj) { (obj || {}).delete(:object_id) }
18
+ delete_object_id.call(event[:receiver])
19
+ delete_object_id.call(event[:return_value])
20
+ (event[:parameters] || []).each(&delete_object_id)
21
+ (event[:exceptions] || []).each(&delete_object_id)
22
+
23
+ if event[:event] == :return
24
+ # These should be removed from the appmap spec
25
+ %i[defined_class method_id path lineno static].each do |obsolete_field|
26
+ event.delete(obsolete_field)
27
+ end
28
+ end
29
+ event
30
+ end.to_yaml
31
+ end
32
+
33
+ def invoke_test_file(file, &block)
34
+ package = AppMap::Hook::Package.new(file, [])
35
+ config = AppMap::Hook::Config.new('hook_spec', [ package ])
36
+ AppMap::Hook.hook(config)
37
+
38
+ tracer = AppMap.tracing.trace
39
+ AppMap::Event.reset_id_counter
40
+ begin
41
+ load file
42
+ yield
43
+ ensure
44
+ AppMap.tracing.delete(tracer)
45
+ end
46
+ [ config, tracer ]
47
+ end
48
+
49
+ def test_hook_behavior(file, events_yaml, &block)
50
+ config, tracer = invoke_test_file(file, &block)
51
+
52
+ events = collect_events(tracer)
53
+ expect(Diffy::Diff.new(events, events_yaml).to_s).to eq('')
54
+
55
+ [ config, tracer ]
56
+ end
57
+
58
+ it 'hooks an instance method that takes no arguments' do
59
+ events_yaml = <<~YAML
60
+ ---
61
+ - :id: 1
62
+ :event: :call
63
+ :defined_class: InstanceMethod
64
+ :method_id: say_default
65
+ :path: spec/fixtures/hook/instance_method.rb
66
+ :lineno: 8
67
+ :static: false
68
+ :parameters: []
69
+ :receiver:
70
+ :class: InstanceMethod
71
+ :value: Instance Method fixture
72
+ - :id: 2
73
+ :event: :return
74
+ :parent_id: 1
75
+ :return_value:
76
+ :class: String
77
+ :value: default
78
+ YAML
79
+ config, tracer = test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
80
+ expect(InstanceMethod.new.say_default).to eq('default')
81
+ end
82
+ end
83
+
84
+ it 'collects the methods that are invoked' do
85
+ _, tracer = invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
86
+ InstanceMethod.new.say_default
87
+ end
88
+ expect(tracer.event_methods.to_a.map(&:defined_class)).to eq([ 'InstanceMethod' ])
89
+ expect(tracer.event_methods.to_a.map(&:method).map(&:to_s)).to eq([ InstanceMethod.public_instance_method(:say_default).to_s ])
90
+ end
91
+
92
+ it 'builds a class map of invoked methods' do
93
+ config, tracer = invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
94
+ InstanceMethod.new.say_default
95
+ end
96
+ class_map = AppMap.class_map(config, tracer.event_methods).to_yaml
97
+ expect(Diffy::Diff.new(class_map, <<~YAML).to_s).to eq('')
98
+ ---
99
+ - :name: spec/fixtures/hook/instance_method.rb
100
+ :type: package
101
+ :children:
102
+ - :name: InstanceMethod
103
+ :type: class
104
+ :children:
105
+ - :name: say_default
106
+ :type: function
107
+ :location: spec/fixtures/hook/instance_method.rb:8
108
+ :static: false
109
+ YAML
110
+ end
111
+
112
+ it 'does not hook an attr_accessor' do
113
+ events_yaml = <<~YAML
114
+ --- []
115
+ YAML
116
+ test_hook_behavior 'spec/fixtures/hook/attr_accessor.rb', events_yaml do
117
+ obj = AttrAccessor.new
118
+ obj.value = 'foo'
119
+ expect(obj.value).to eq('foo')
120
+ end
121
+ end
122
+
123
+ it 'does not hook a constructor' do
124
+ events_yaml = <<~YAML
125
+ --- []
126
+ YAML
127
+ test_hook_behavior 'spec/fixtures/hook/constructor.rb', events_yaml do
128
+ Constructor.new('foo')
129
+ end
130
+ end
131
+
132
+ it 'hooks an instance method that takes an argument' do
133
+ events_yaml = <<~YAML
134
+ ---
135
+ - :id: 1
136
+ :event: :call
137
+ :defined_class: InstanceMethod
138
+ :method_id: say_echo
139
+ :path: spec/fixtures/hook/instance_method.rb
140
+ :lineno: 12
141
+ :static: false
142
+ :parameters:
143
+ - :name: :arg
144
+ :class: String
145
+ :value: echo
146
+ :kind: :req
147
+ :receiver:
148
+ :class: InstanceMethod
149
+ :value: Instance Method fixture
150
+ - :id: 2
151
+ :event: :return
152
+ :parent_id: 1
153
+ :return_value:
154
+ :class: String
155
+ :value: echo
156
+ YAML
157
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
158
+ expect(InstanceMethod.new.say_echo('echo')).to eq('echo')
159
+ end
160
+ end
161
+
162
+ it 'hooks an instance method that takes a keyword argument' do
163
+ events_yaml = <<~YAML
164
+ ---
165
+ - :id: 1
166
+ :event: :call
167
+ :defined_class: InstanceMethod
168
+ :method_id: say_kw
169
+ :path: spec/fixtures/hook/instance_method.rb
170
+ :lineno: 16
171
+ :static: false
172
+ :parameters:
173
+ - :name: :kw
174
+ :class: Hash
175
+ :value: '{:kw=>"kw"}'
176
+ :kind: :key
177
+ :receiver:
178
+ :class: InstanceMethod
179
+ :value: Instance Method fixture
180
+ - :id: 2
181
+ :event: :return
182
+ :parent_id: 1
183
+ :return_value:
184
+ :class: String
185
+ :value: kw
186
+ YAML
187
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
188
+ expect(InstanceMethod.new.say_kw(kw: 'kw')).to eq('kw')
189
+ end
190
+ end
191
+
192
+ it 'hooks an instance method that takes a default keyword argument' do
193
+ events_yaml = <<~YAML
194
+ ---
195
+ - :id: 1
196
+ :event: :call
197
+ :defined_class: InstanceMethod
198
+ :method_id: say_kw
199
+ :path: spec/fixtures/hook/instance_method.rb
200
+ :lineno: 16
201
+ :static: false
202
+ :parameters:
203
+ - :name: :kw
204
+ :class: NilClass
205
+ :value:
206
+ :kind: :key
207
+ :receiver:
208
+ :class: InstanceMethod
209
+ :value: Instance Method fixture
210
+ - :id: 2
211
+ :event: :return
212
+ :parent_id: 1
213
+ :return_value:
214
+ :class: String
215
+ :value: kw
216
+ YAML
217
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
218
+ expect(InstanceMethod.new.say_kw).to eq('kw')
219
+ end
220
+ end
221
+
222
+ it 'hooks an instance method that takes a block argument' do
223
+ events_yaml = <<~YAML
224
+ ---
225
+ - :id: 1
226
+ :event: :call
227
+ :defined_class: InstanceMethod
228
+ :method_id: say_block
229
+ :path: spec/fixtures/hook/instance_method.rb
230
+ :lineno: 20
231
+ :static: false
232
+ :parameters:
233
+ - :name: :block
234
+ :class: NilClass
235
+ :value:
236
+ :kind: :block
237
+ :receiver:
238
+ :class: InstanceMethod
239
+ :value: Instance Method fixture
240
+ - :id: 2
241
+ :event: :return
242
+ :parent_id: 1
243
+ :return_value:
244
+ :class: String
245
+ :value: albert
246
+ YAML
247
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
248
+ expect(InstanceMethod.new.say_block { 'albert' }).to eq('albert')
249
+ end
250
+ end
251
+
252
+ it 'hooks a singleton method' do
253
+ events_yaml = <<~YAML
254
+ ---
255
+ - :id: 1
256
+ :event: :call
257
+ :defined_class: ClassMethod
258
+ :method_id: say_default
259
+ :path: spec/fixtures/hook/class_method.rb
260
+ :lineno: 5
261
+ :static: true
262
+ :parameters: []
263
+ :receiver:
264
+ :class: Class
265
+ :value: ClassMethod
266
+ - :id: 2
267
+ :event: :return
268
+ :parent_id: 1
269
+ :return_value:
270
+ :class: String
271
+ :value: default
272
+ YAML
273
+ test_hook_behavior 'spec/fixtures/hook/class_method.rb', events_yaml do
274
+ expect(ClassMethod.say_default).to eq('default')
275
+ end
276
+ end
277
+
278
+ it 'hooks a class method with explicit class name scope' do
279
+ events_yaml = <<~YAML
280
+ ---
281
+ - :id: 1
282
+ :event: :call
283
+ :defined_class: ClassMethod
284
+ :method_id: say_class_defined
285
+ :path: spec/fixtures/hook/class_method.rb
286
+ :lineno: 10
287
+ :static: true
288
+ :parameters: []
289
+ :receiver:
290
+ :class: Class
291
+ :value: ClassMethod
292
+ - :id: 2
293
+ :event: :return
294
+ :parent_id: 1
295
+ :return_value:
296
+ :class: String
297
+ :value: defined with explicit class scope
298
+ YAML
299
+ test_hook_behavior 'spec/fixtures/hook/class_method.rb', events_yaml do
300
+ expect(ClassMethod.say_class_defined).to eq('defined with explicit class scope')
301
+ end
302
+ end
303
+
304
+ it "hooks a class method with 'self' as the class name scope" do
305
+ events_yaml = <<~YAML
306
+ ---
307
+ - :id: 1
308
+ :event: :call
309
+ :defined_class: ClassMethod
310
+ :method_id: say_self_defined
311
+ :path: spec/fixtures/hook/class_method.rb
312
+ :lineno: 14
313
+ :static: true
314
+ :parameters: []
315
+ :receiver:
316
+ :class: Class
317
+ :value: ClassMethod
318
+ - :id: 2
319
+ :event: :return
320
+ :parent_id: 1
321
+ :return_value:
322
+ :class: String
323
+ :value: defined with self class scope
324
+ YAML
325
+ test_hook_behavior 'spec/fixtures/hook/class_method.rb', events_yaml do
326
+ expect(ClassMethod.say_self_defined).to eq('defined with self class scope')
327
+ end
328
+ end
329
+
330
+ it 'Reports exceptions' do
331
+ events_yaml = <<~YAML
332
+ ---
333
+ - :id: 1
334
+ :event: :call
335
+ :defined_class: ExceptionMethod
336
+ :method_id: raise_exception
337
+ :path: spec/fixtures/hook/exception_method.rb
338
+ :lineno: 8
339
+ :static: false
340
+ :parameters: []
341
+ :receiver:
342
+ :class: ExceptionMethod
343
+ :value: Exception Method fixture
344
+ - :id: 2
345
+ :event: :return
346
+ :parent_id: 1
347
+ :exceptions:
348
+ - :class: RuntimeError
349
+ :message: Exception occurred in raise_exception
350
+ :path: spec/fixtures/hook/exception_method.rb
351
+ :lineno: 9
352
+ YAML
353
+ test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
354
+ ExceptionMethod.new.raise_exception
355
+ end
356
+ end
357
+ end