rotoscope 0.2.2 → 0.3.0.pre.1
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 +4 -4
- data/ext/rotoscope/rotoscope.c +71 -72
- data/ext/rotoscope/rotoscope.h +12 -11
- data/ext/rotoscope/stack.c +5 -4
- data/ext/rotoscope/stack.h +2 -1
- data/lib/rotoscope/version.rb +4 -0
- data/rotoscope.gemspec +10 -4
- metadata +7 -9
- data/test/fixture_inner.rb +0 -10
- data/test/fixture_outer.rb +0 -10
- data/test/monadify.rb +0 -16
- data/test/rotoscope_test.rb +0 -482
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a94009a6d6ee2a34d124e8b922feb3ff3eda7f2
|
4
|
+
data.tar.gz: eab31fe889c50ea034197aa1a435ccb22c832630
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ab381c724461c0b5dbab3a8dbbbf3e451c5aae060b8aecbaa9f28abc4d7aa636ecf7cd451b68537e104e13fc53c45243c47e4b44b48875f58bf1e32902a3f58
|
7
|
+
data.tar.gz: 5a598811ac79f0524d0e2d93d28a727a51e296cb575ed1de9b98e0f1b3921927b8557873e0bdcc682b8f7d09136f6d347c5d6eb2f8a7192bf39355a01e26f228
|
data/ext/rotoscope/rotoscope.c
CHANGED
@@ -14,9 +14,7 @@
|
|
14
14
|
#include "tracepoint.h"
|
15
15
|
|
16
16
|
VALUE cRotoscope, cTracePoint;
|
17
|
-
|
18
|
-
// recursive with singleton2str
|
19
|
-
static rs_class_desc_t class2str(VALUE klass);
|
17
|
+
ID id_initialize;
|
20
18
|
|
21
19
|
static unsigned long gettid() {
|
22
20
|
return NUM2ULONG(rb_obj_id(rb_thread_current()));
|
@@ -47,46 +45,27 @@ static bool rejected_path(VALUE path, Rotoscope *config) {
|
|
47
45
|
return false;
|
48
46
|
}
|
49
47
|
|
50
|
-
static VALUE
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
static bool is_class_singleton(VALUE klass) {
|
55
|
-
VALUE obj = class_of_singleton(klass);
|
56
|
-
return (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS));
|
57
|
-
}
|
58
|
-
|
59
|
-
static VALUE singleton2str(VALUE klass) {
|
60
|
-
if (is_class_singleton(klass)) {
|
61
|
-
VALUE obj = class_of_singleton(klass);
|
62
|
-
VALUE cached_lookup = rb_class_path_cached(obj);
|
63
|
-
VALUE name = (NIL_P(cached_lookup)) ? rb_class_name(obj) : cached_lookup;
|
64
|
-
return name;
|
65
|
-
} else // singleton of an instance
|
66
|
-
{
|
67
|
-
return singleton2str(CLASS_OF(klass));
|
48
|
+
static VALUE class_path(VALUE klass) {
|
49
|
+
VALUE cached_path = rb_class_path_cached(klass);
|
50
|
+
if (!NIL_P(cached_path)) {
|
51
|
+
return cached_path;
|
68
52
|
}
|
53
|
+
return rb_class_path(klass);
|
69
54
|
}
|
70
55
|
|
71
|
-
static
|
72
|
-
|
73
|
-
|
56
|
+
static VALUE singleton_object(VALUE singleton_class) {
|
57
|
+
return rb_iv_get(singleton_class, "__attached__");
|
58
|
+
}
|
74
59
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
if (is_class_singleton(klass)) {
|
82
|
-
real_class.method_level = CLASS_METHOD;
|
83
|
-
}
|
84
|
-
} else {
|
85
|
-
real_class.name = rb_class_path(klass);
|
60
|
+
static VALUE class2str(VALUE klass) {
|
61
|
+
while (FL_TEST(klass, FL_SINGLETON)) {
|
62
|
+
klass = singleton_object(klass);
|
63
|
+
if (!RB_TYPE_P(klass, T_MODULE) && !RB_TYPE_P(klass, T_CLASS)) {
|
64
|
+
// singleton of an instance
|
65
|
+
klass = rb_obj_class(klass);
|
86
66
|
}
|
87
67
|
}
|
88
|
-
|
89
|
-
return real_class;
|
68
|
+
return class_path(klass);
|
90
69
|
}
|
91
70
|
|
92
71
|
static rs_callsite_t tracearg_path(rb_trace_arg_t *trace_arg) {
|
@@ -101,19 +80,21 @@ static rs_callsite_t tracearg_path(rb_trace_arg_t *trace_arg) {
|
|
101
80
|
|
102
81
|
static rs_class_desc_t tracearg_class(rb_trace_arg_t *trace_arg) {
|
103
82
|
VALUE klass;
|
83
|
+
const char *method_level;
|
104
84
|
VALUE self = rb_tracearg_self(trace_arg);
|
105
85
|
|
106
|
-
if (RB_TYPE_P(self,
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
// If not, name based on self instead of its singleton
|
111
|
-
klass = (FL_TEST(CLASS_OF(self), FL_SINGLETON)) ? CLASS_OF(self) : self;
|
86
|
+
if ((RB_TYPE_P(self, T_CLASS) || RB_TYPE_P(self, T_MODULE)) &&
|
87
|
+
SYM2ID(rb_tracearg_method_id(trace_arg)) != id_initialize) {
|
88
|
+
method_level = CLASS_METHOD;
|
89
|
+
klass = self;
|
112
90
|
} else {
|
113
|
-
|
91
|
+
method_level = INSTANCE_METHOD;
|
92
|
+
klass = rb_obj_class(self);
|
114
93
|
}
|
115
94
|
|
116
|
-
return
|
95
|
+
return (rs_class_desc_t){
|
96
|
+
.name = class2str(klass), .method_level = method_level,
|
97
|
+
};
|
117
98
|
}
|
118
99
|
|
119
100
|
static VALUE tracearg_method_name(rb_trace_arg_t *trace_arg) {
|
@@ -138,30 +119,24 @@ static rs_tracepoint_t extract_full_tracevals(rb_trace_arg_t *trace_arg,
|
|
138
119
|
|
139
120
|
static bool in_fork(Rotoscope *config) { return config->pid != getpid(); }
|
140
121
|
|
141
|
-
static
|
142
|
-
return (!rb_str_cmp(a->method_name, b->method_name) &&
|
143
|
-
!rb_str_cmp(a->entity, b->entity) &&
|
144
|
-
a->method_level == b->method_level);
|
145
|
-
}
|
146
|
-
|
147
|
-
static void log_raw_trace(FILE *stream, rs_tracepoint_t trace) {
|
122
|
+
static void log_trace_event(FILE *stream, rs_tracepoint_t *trace) {
|
148
123
|
fprintf(stream, RS_CSV_FORMAT "\n", RS_CSV_VALUES(trace));
|
149
124
|
}
|
150
125
|
|
151
|
-
unsigned char output_buffer[
|
152
|
-
static void
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
126
|
+
unsigned char output_buffer[LOG_BUFFER_SIZE];
|
127
|
+
static void log_trace_event_with_caller(FILE *stream,
|
128
|
+
rs_stack_frame_t *stack_frame,
|
129
|
+
rs_strmemo_t **call_memo) {
|
130
|
+
rs_stack_frame_t *caller = stack_frame->caller;
|
131
|
+
while (caller->blacklisted) {
|
132
|
+
caller = caller->caller;
|
133
|
+
}
|
134
|
+
|
135
|
+
snprintf((char *)output_buffer, LOG_BUFFER_SIZE, RS_FLATTENED_CSV_FORMAT "\n",
|
136
|
+
RS_FLATTENED_CSV_VALUES(&stack_frame->tp, &caller->tp));
|
137
|
+
|
138
|
+
if (rs_strmemo_uniq(call_memo, output_buffer)) {
|
139
|
+
fputs((char *)output_buffer, stream);
|
165
140
|
}
|
166
141
|
}
|
167
142
|
|
@@ -176,19 +151,40 @@ static void event_hook(VALUE tpval, void *data) {
|
|
176
151
|
}
|
177
152
|
|
178
153
|
rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpval);
|
179
|
-
|
154
|
+
rb_event_flag_t event_flag = rb_tracearg_event_flag(trace_arg);
|
180
155
|
|
181
|
-
|
156
|
+
rs_callsite_t trace_path;
|
157
|
+
bool blacklisted;
|
158
|
+
if (event_flag & EVENT_CALL) {
|
159
|
+
trace_path = tracearg_path(trace_arg);
|
160
|
+
blacklisted = rejected_path(trace_path.filepath, config);
|
161
|
+
} else {
|
162
|
+
if (rs_stack_empty(&config->stack)) return;
|
163
|
+
rs_stack_frame_t *call_frame = rs_stack_peek(&config->stack);
|
164
|
+
trace_path = (rs_callsite_t){
|
165
|
+
.filepath = call_frame->tp.filepath, .lineno = call_frame->tp.lineno,
|
166
|
+
};
|
167
|
+
blacklisted = call_frame->blacklisted;
|
168
|
+
}
|
182
169
|
|
183
170
|
rs_tracepoint_t trace = extract_full_tracevals(trace_arg, &trace_path);
|
184
171
|
if (!strcmp("Rotoscope", StringValueCStr(trace.entity))) return;
|
185
172
|
|
173
|
+
if (event_flag & EVENT_CALL) {
|
174
|
+
rs_stack_push(&config->stack, trace, blacklisted);
|
175
|
+
} else {
|
176
|
+
rs_stack_pop(&config->stack);
|
177
|
+
}
|
178
|
+
|
179
|
+
if (blacklisted) return;
|
180
|
+
|
186
181
|
if (config->flatten_output) {
|
187
|
-
|
188
|
-
|
189
|
-
|
182
|
+
if (event_flag & EVENT_CALL) {
|
183
|
+
log_trace_event_with_caller(config->log, rs_stack_peek(&config->stack),
|
184
|
+
&config->call_memo);
|
185
|
+
}
|
190
186
|
} else {
|
191
|
-
|
187
|
+
log_trace_event(config->log, &trace);
|
192
188
|
}
|
193
189
|
}
|
194
190
|
|
@@ -317,6 +313,7 @@ VALUE rotoscope_stop_trace(VALUE self) {
|
|
317
313
|
if (rb_tracepoint_enabled_p(config->tracepoint)) {
|
318
314
|
rb_tracepoint_disable(config->tracepoint);
|
319
315
|
config->state = RS_OPEN;
|
316
|
+
rs_stack_reset(&config->stack, STACK_CAPACITY);
|
320
317
|
}
|
321
318
|
|
322
319
|
return Qnil;
|
@@ -373,6 +370,8 @@ VALUE rotoscope_state(VALUE self) {
|
|
373
370
|
void Init_rotoscope(void) {
|
374
371
|
cTracePoint = rb_const_get(rb_cObject, rb_intern("TracePoint"));
|
375
372
|
|
373
|
+
id_initialize = rb_intern("initialize");
|
374
|
+
|
376
375
|
cRotoscope = rb_define_class("Rotoscope", rb_cObject);
|
377
376
|
rb_define_alloc_func(cRotoscope, rs_alloc);
|
378
377
|
rb_define_method(cRotoscope, "initialize", initialize, -1);
|
data/ext/rotoscope/rotoscope.h
CHANGED
@@ -12,29 +12,30 @@
|
|
12
12
|
#define INSTANCE_METHOD "instance"
|
13
13
|
|
14
14
|
#define STACK_CAPACITY 500
|
15
|
+
#define LOG_BUFFER_SIZE 1000
|
15
16
|
|
16
17
|
// clang-format off
|
17
18
|
#define _RS_COMMON_CSV_HEADER "entity,method_name,method_level,filepath,lineno"
|
18
19
|
#define _RS_COMMON_CSV_FORMAT "\"%s\",\"%s\",%s,\"%s\",%d"
|
19
20
|
#define _RS_COMMON_CSV_VALUES(trace) \
|
20
|
-
StringValueCStr(trace
|
21
|
-
StringValueCStr(trace
|
22
|
-
trace
|
23
|
-
StringValueCStr(trace
|
24
|
-
trace
|
21
|
+
StringValueCStr((trace)->entity), \
|
22
|
+
StringValueCStr((trace)->method_name), \
|
23
|
+
(trace)->method_level, \
|
24
|
+
StringValueCStr((trace)->filepath), \
|
25
|
+
(trace)->lineno
|
25
26
|
|
26
27
|
#define RS_CSV_HEADER "event," _RS_COMMON_CSV_HEADER
|
27
28
|
#define RS_CSV_FORMAT "%s," _RS_COMMON_CSV_FORMAT
|
28
|
-
#define RS_CSV_VALUES(trace) trace
|
29
|
+
#define RS_CSV_VALUES(trace) trace->event, _RS_COMMON_CSV_VALUES(trace)
|
29
30
|
|
30
31
|
#define RS_FLATTENED_CSV_HEADER \
|
31
32
|
_RS_COMMON_CSV_HEADER ",caller_entity,caller_method_name,caller_method_level"
|
32
33
|
#define RS_FLATTENED_CSV_FORMAT _RS_COMMON_CSV_FORMAT ",\"%s\",\"%s\",%s"
|
33
|
-
#define RS_FLATTENED_CSV_VALUES(
|
34
|
-
_RS_COMMON_CSV_VALUES(
|
35
|
-
StringValueCStr(
|
36
|
-
StringValueCStr(
|
37
|
-
|
34
|
+
#define RS_FLATTENED_CSV_VALUES(trace, caller_trace) \
|
35
|
+
_RS_COMMON_CSV_VALUES(trace), \
|
36
|
+
StringValueCStr((caller_trace)->entity), \
|
37
|
+
StringValueCStr((caller_trace)->method_name), \
|
38
|
+
(caller_trace)->method_level
|
38
39
|
// clang-format on
|
39
40
|
|
40
41
|
typedef enum {
|
data/ext/rotoscope/stack.c
CHANGED
@@ -14,7 +14,7 @@ static void insert_root_node(rs_stack_t *stack) {
|
|
14
14
|
.method_name = rb_unknown_str,
|
15
15
|
.method_level = UNKNOWN_STR,
|
16
16
|
.lineno = 0};
|
17
|
-
rs_stack_push(stack, root_trace);
|
17
|
+
rs_stack_push(stack, root_trace, false);
|
18
18
|
}
|
19
19
|
|
20
20
|
static void resize_buffer(rs_stack_t *stack) {
|
@@ -31,15 +31,16 @@ bool rs_stack_full(rs_stack_t *stack) {
|
|
31
31
|
|
32
32
|
bool rs_stack_empty(rs_stack_t *stack) { return stack->top < 0; }
|
33
33
|
|
34
|
-
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace
|
34
|
+
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace,
|
35
|
+
bool blacklisted) {
|
35
36
|
if (rs_stack_full(stack)) {
|
36
37
|
resize_buffer(stack);
|
37
38
|
}
|
38
39
|
|
39
40
|
rs_stack_frame_t *caller =
|
40
41
|
rs_stack_empty(stack) ? NULL : rs_stack_peek(stack);
|
41
|
-
rs_stack_frame_t new_frame =
|
42
|
-
|
42
|
+
rs_stack_frame_t new_frame = (rs_stack_frame_t){
|
43
|
+
.tp = trace, .caller = caller, .blacklisted = blacklisted};
|
43
44
|
|
44
45
|
stack->contents[++stack->top] = new_frame;
|
45
46
|
return new_frame;
|
data/ext/rotoscope/stack.h
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
typedef struct rs_stack_frame_t {
|
9
9
|
struct rs_tracepoint_t tp;
|
10
|
+
bool blacklisted;
|
10
11
|
struct rs_stack_frame_t *caller;
|
11
12
|
} rs_stack_frame_t;
|
12
13
|
|
@@ -19,7 +20,7 @@ typedef struct {
|
|
19
20
|
void rs_stack_init(rs_stack_t *stack, unsigned int capacity);
|
20
21
|
void rs_stack_reset(rs_stack_t *stack, unsigned int capacity);
|
21
22
|
void rs_stack_free(rs_stack_t *stack);
|
22
|
-
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace);
|
23
|
+
rs_stack_frame_t rs_stack_push(rs_stack_t *stack, rs_tracepoint_t trace, bool backlisted);
|
23
24
|
bool rs_stack_empty(rs_stack_t *stack);
|
24
25
|
bool rs_stack_full(rs_stack_t *stack);
|
25
26
|
rs_stack_frame_t rs_stack_pop(rs_stack_t *stack);
|
data/rotoscope.gemspec
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "rotoscope/version"
|
5
|
+
|
2
6
|
Gem::Specification.new do |s|
|
3
7
|
s.name = 'rotoscope'
|
4
|
-
s.version =
|
5
|
-
s.date = '2017-09-
|
8
|
+
s.version = Rotoscope::VERSION
|
9
|
+
s.date = '2017-09-20'
|
6
10
|
|
7
|
-
s.authors = ["Jahfer Husain"]
|
11
|
+
s.authors = ["Jahfer Husain", "Dylan Thacker-Smith"]
|
8
12
|
s.email = 'jahfer.husain@shopify.com'
|
9
13
|
s.homepage = 'https://github.com/shopify/rotoscope'
|
10
14
|
s.license = 'MIT'
|
@@ -12,7 +16,9 @@ Gem::Specification.new do |s|
|
|
12
16
|
s.summary = "Tracing Ruby"
|
13
17
|
s.description = "High-performance logger of Ruby method invocations"
|
14
18
|
|
15
|
-
s.files = `git ls-files`.split("\
|
19
|
+
s.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test)/})
|
21
|
+
end
|
16
22
|
s.required_ruby_version = ">= 2.2.0"
|
17
23
|
s.extensions = %w(ext/rotoscope/extconf.rb)
|
18
24
|
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rotoscope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jahfer Husain
|
8
|
+
- Dylan Thacker-Smith
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
12
|
+
date: 2017-09-20 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rake-compiler
|
@@ -96,12 +97,9 @@ files:
|
|
96
97
|
- ext/rotoscope/tracepoint.c
|
97
98
|
- ext/rotoscope/tracepoint.h
|
98
99
|
- lib/rotoscope.rb
|
100
|
+
- lib/rotoscope/version.rb
|
99
101
|
- lib/uthash/uthash.h
|
100
102
|
- rotoscope.gemspec
|
101
|
-
- test/fixture_inner.rb
|
102
|
-
- test/fixture_outer.rb
|
103
|
-
- test/monadify.rb
|
104
|
-
- test/rotoscope_test.rb
|
105
103
|
homepage: https://github.com/shopify/rotoscope
|
106
104
|
licenses:
|
107
105
|
- MIT
|
@@ -117,12 +115,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
115
|
version: 2.2.0
|
118
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
117
|
requirements:
|
120
|
-
- - "
|
118
|
+
- - ">"
|
121
119
|
- !ruby/object:Gem::Version
|
122
|
-
version:
|
120
|
+
version: 1.3.1
|
123
121
|
requirements: []
|
124
122
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.6.
|
123
|
+
rubygems_version: 2.6.13
|
126
124
|
signing_key:
|
127
125
|
specification_version: 4
|
128
126
|
summary: Tracing Ruby
|
data/test/fixture_inner.rb
DELETED
data/test/fixture_outer.rb
DELETED
data/test/monadify.rb
DELETED
data/test/rotoscope_test.rb
DELETED
@@ -1,482 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift File.expand_path('../', __FILE__)
|
4
|
-
require 'rotoscope'
|
5
|
-
require 'minitest'
|
6
|
-
require 'zlib'
|
7
|
-
require 'fileutils'
|
8
|
-
require 'csv'
|
9
|
-
|
10
|
-
require 'fixture_inner'
|
11
|
-
require 'fixture_outer'
|
12
|
-
require 'monadify'
|
13
|
-
|
14
|
-
module MyModule
|
15
|
-
def module_method; end
|
16
|
-
end
|
17
|
-
|
18
|
-
module PrependedModule
|
19
|
-
def prepended_method; end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Example
|
23
|
-
prepend PrependedModule
|
24
|
-
include MyModule
|
25
|
-
extend MyModule
|
26
|
-
extend Monadify
|
27
|
-
|
28
|
-
class << self
|
29
|
-
def singleton_method
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
def apply(val)
|
34
|
-
monad val
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def normal_method
|
39
|
-
true
|
40
|
-
end
|
41
|
-
|
42
|
-
def exception_method
|
43
|
-
oops
|
44
|
-
rescue
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
def yielding_method
|
49
|
-
yield
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def oops
|
55
|
-
raise "I've made a terrible mistake"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
ROOT_FIXTURE_PATH = File.expand_path('../', __FILE__)
|
60
|
-
INNER_FIXTURE_PATH = File.expand_path('../fixture_inner.rb', __FILE__)
|
61
|
-
OUTER_FIXTURE_PATH = File.expand_path('../fixture_outer.rb', __FILE__)
|
62
|
-
MONADIFY_PATH = File.expand_path('monadify.rb', ROOT_FIXTURE_PATH)
|
63
|
-
|
64
|
-
class RotoscopeTest < MiniTest::Test
|
65
|
-
def setup
|
66
|
-
@logfile = File.expand_path('tmp/test.csv')
|
67
|
-
end
|
68
|
-
|
69
|
-
def teardown
|
70
|
-
FileUtils.remove_file(@logfile) if File.file?(@logfile)
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_new
|
74
|
-
rs = Rotoscope.new(@logfile, blacklist: ['tmp'], flatten: true)
|
75
|
-
assert rs.is_a?(Rotoscope)
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_close
|
79
|
-
rs = Rotoscope.new(@logfile)
|
80
|
-
assert rs.close
|
81
|
-
end
|
82
|
-
|
83
|
-
def test_closed?
|
84
|
-
rs = Rotoscope.new(@logfile)
|
85
|
-
refute_predicate rs, :closed?
|
86
|
-
rs.close
|
87
|
-
assert_predicate rs, :closed?
|
88
|
-
end
|
89
|
-
|
90
|
-
def test_state
|
91
|
-
rs = Rotoscope.new(@logfile)
|
92
|
-
assert_equal :open, rs.state
|
93
|
-
rs.trace do
|
94
|
-
assert_equal :tracing, rs.state
|
95
|
-
end
|
96
|
-
assert_equal :open, rs.state
|
97
|
-
rs.close
|
98
|
-
assert_equal :closed, rs.state
|
99
|
-
end
|
100
|
-
|
101
|
-
def test_mark
|
102
|
-
contents = rotoscope_trace do |rs|
|
103
|
-
Example.new.normal_method
|
104
|
-
rs.mark
|
105
|
-
end
|
106
|
-
|
107
|
-
assert_includes contents.split("\n"), '--- '
|
108
|
-
end
|
109
|
-
|
110
|
-
def test_mark_with_custom_strings
|
111
|
-
mark_strings = ["Hello", "ÅÉÎØÜ åéîøü"]
|
112
|
-
contents = rotoscope_trace do |rs|
|
113
|
-
e = Example.new
|
114
|
-
e.normal_method
|
115
|
-
mark_strings.each { |str| rs.mark(str) }
|
116
|
-
end
|
117
|
-
|
118
|
-
content_lines = contents.split("\n")
|
119
|
-
mark_strings.each do |str|
|
120
|
-
assert_includes content_lines, "--- #{str}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def test_flatten
|
125
|
-
contents = rotoscope_trace(flatten: true) do
|
126
|
-
Example.new.normal_method
|
127
|
-
end
|
128
|
-
|
129
|
-
assert_equal [
|
130
|
-
{ entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
131
|
-
{ entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "Example", caller_method_name: "new", caller_method_level: "class" },
|
132
|
-
{ entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
133
|
-
], parse_and_normalize(contents)
|
134
|
-
end
|
135
|
-
|
136
|
-
def test_flatten_removes_duplicates
|
137
|
-
contents = rotoscope_trace(flatten: true) do
|
138
|
-
e = Example.new
|
139
|
-
10.times { e.normal_method }
|
140
|
-
end
|
141
|
-
|
142
|
-
assert_equal [
|
143
|
-
{ entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
144
|
-
{ entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "Example", caller_method_name: "new", caller_method_level: "class" },
|
145
|
-
{ entity: "Integer", method_name: "times", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
146
|
-
{ entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "Integer", caller_method_name: "times", caller_method_level: "instance" },
|
147
|
-
], parse_and_normalize(contents)
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_start_trace_and_stop_trace
|
151
|
-
rs = Rotoscope.new(@logfile)
|
152
|
-
rs.start_trace
|
153
|
-
Example.new.normal_method
|
154
|
-
rs.stop_trace
|
155
|
-
rs.close
|
156
|
-
contents = File.read(@logfile)
|
157
|
-
|
158
|
-
assert_equal [
|
159
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
160
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
161
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
162
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
163
|
-
{ event: "call", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
164
|
-
{ event: "return", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
165
|
-
], parse_and_normalize(contents)
|
166
|
-
|
167
|
-
assert_frames_consistent contents
|
168
|
-
end
|
169
|
-
|
170
|
-
def test_traces_instance_method
|
171
|
-
contents = rotoscope_trace { Example.new.normal_method }
|
172
|
-
assert_equal [
|
173
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
174
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
175
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
176
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
177
|
-
{ event: "call", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
178
|
-
{ event: "return", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 }
|
179
|
-
], parse_and_normalize(contents)
|
180
|
-
|
181
|
-
assert_frames_consistent contents
|
182
|
-
end
|
183
|
-
|
184
|
-
def test_traces_yielding_method
|
185
|
-
contents = rotoscope_trace do
|
186
|
-
e = Example.new
|
187
|
-
e.yielding_method { e.normal_method }
|
188
|
-
end
|
189
|
-
|
190
|
-
assert_equal [
|
191
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
192
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
193
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
194
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
195
|
-
{ event: "call", entity: "Example", method_name: "yielding_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
196
|
-
{ event: "call", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
197
|
-
{ event: "return", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
198
|
-
{ event: "return", entity: "Example", method_name: "yielding_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 }
|
199
|
-
], parse_and_normalize(contents)
|
200
|
-
|
201
|
-
assert_frames_consistent contents
|
202
|
-
end
|
203
|
-
|
204
|
-
def test_calls_are_consistent_after_exception
|
205
|
-
contents = rotoscope_trace { Example.new.exception_method }
|
206
|
-
assert_frames_consistent contents
|
207
|
-
end
|
208
|
-
|
209
|
-
def test_traces_and_formats_singletons_of_a_class
|
210
|
-
contents = rotoscope_trace { Example.singleton_method }
|
211
|
-
assert_equal [
|
212
|
-
{ event: "call", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
213
|
-
{ event: "return", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 }
|
214
|
-
], parse_and_normalize(contents)
|
215
|
-
|
216
|
-
assert_frames_consistent contents
|
217
|
-
end
|
218
|
-
|
219
|
-
def test_traces_and_formats_singletons_of_an_instance
|
220
|
-
contents = rotoscope_trace { Example.new.singleton_class.singleton_method }
|
221
|
-
assert_equal [
|
222
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
223
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
224
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
225
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
226
|
-
{ event: "call", entity: "Example", method_name: "singleton_class", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
227
|
-
{ event: "return", entity: "Example", method_name: "singleton_class", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
228
|
-
{ event: "call", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
229
|
-
{ event: "return", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
230
|
-
], parse_and_normalize(contents)
|
231
|
-
|
232
|
-
assert_frames_consistent contents
|
233
|
-
end
|
234
|
-
|
235
|
-
def test_traces_included_module_method
|
236
|
-
contents = rotoscope_trace { Example.new.module_method }
|
237
|
-
assert_equal [
|
238
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
239
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
240
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
241
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
242
|
-
{ event: "call", entity: "Example", method_name: "module_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
243
|
-
{ event: "return", entity: "Example", method_name: "module_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 }
|
244
|
-
], parse_and_normalize(contents)
|
245
|
-
|
246
|
-
assert_frames_consistent contents
|
247
|
-
end
|
248
|
-
|
249
|
-
def test_traces_extended_module_method
|
250
|
-
contents = rotoscope_trace { Example.module_method }
|
251
|
-
assert_equal [
|
252
|
-
{ event: "call", entity: "Example", method_name: "module_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
253
|
-
{ event: "return", entity: "Example", method_name: "module_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 }
|
254
|
-
], parse_and_normalize(contents)
|
255
|
-
|
256
|
-
assert_frames_consistent contents
|
257
|
-
end
|
258
|
-
|
259
|
-
def test_traces_prepended_module_method
|
260
|
-
contents = rotoscope_trace { Example.new.prepended_method }
|
261
|
-
assert_equal [
|
262
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
263
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
264
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
265
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
266
|
-
{ event: "call", entity: "Example", method_name: "prepended_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
267
|
-
{ event: "return", entity: "Example", method_name: "prepended_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 }
|
268
|
-
], parse_and_normalize(contents)
|
269
|
-
|
270
|
-
assert_frames_consistent contents
|
271
|
-
end
|
272
|
-
|
273
|
-
def test_trace_ignores_calls_if_blacklisted
|
274
|
-
contents = rotoscope_trace(blacklist: [INNER_FIXTURE_PATH, OUTER_FIXTURE_PATH]) do
|
275
|
-
foo = FixtureOuter.new
|
276
|
-
foo.do_work
|
277
|
-
end
|
278
|
-
|
279
|
-
assert_equal [
|
280
|
-
{ event: "call", entity: "FixtureOuter", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
281
|
-
{ event: "call", entity: "FixtureOuter", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
282
|
-
{ event: "return", entity: "FixtureOuter", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
283
|
-
{ event: "return", entity: "FixtureOuter", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
284
|
-
{ event: "call", entity: "FixtureOuter", method_name: "do_work", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
285
|
-
{ event: "return", entity: "FixtureOuter", method_name: "do_work", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
286
|
-
], parse_and_normalize(contents)
|
287
|
-
|
288
|
-
assert_frames_consistent contents
|
289
|
-
end
|
290
|
-
|
291
|
-
def test_trace_ignores_writes_in_fork
|
292
|
-
contents = rotoscope_trace do |rotoscope|
|
293
|
-
fork do
|
294
|
-
Example.singleton_method
|
295
|
-
rotoscope.mark
|
296
|
-
rotoscope.close
|
297
|
-
end
|
298
|
-
Example.singleton_method
|
299
|
-
Process.wait
|
300
|
-
end
|
301
|
-
assert_equal [
|
302
|
-
{ event: "call", entity: "RotoscopeTest", method_name: "fork", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
303
|
-
{ event: "return", entity: "RotoscopeTest", method_name: "fork", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
304
|
-
{ event: "call", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
305
|
-
{ event: "return", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
306
|
-
{ event: "call", entity: "Process", method_name: "wait", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
307
|
-
{ event: "return", entity: "Process", method_name: "wait", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
308
|
-
], parse_and_normalize(contents)
|
309
|
-
end
|
310
|
-
|
311
|
-
def test_trace_disabled_on_close
|
312
|
-
contents = rotoscope_trace do |rotoscope|
|
313
|
-
Example.singleton_method
|
314
|
-
rotoscope.close
|
315
|
-
rotoscope.mark
|
316
|
-
Example.singleton_method
|
317
|
-
end
|
318
|
-
assert_equal [
|
319
|
-
{ event: "call", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
320
|
-
{ event: "return", entity: "Example", method_name: "singleton_method", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
321
|
-
], parse_and_normalize(contents)
|
322
|
-
end
|
323
|
-
|
324
|
-
def test_trace_flatten
|
325
|
-
contents = rotoscope_trace(flatten: true) { Example.new.normal_method }
|
326
|
-
assert_equal [
|
327
|
-
{ entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
328
|
-
{ entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "Example", caller_method_name: "new", caller_method_level: "class" },
|
329
|
-
{ entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
330
|
-
], parse_and_normalize(contents)
|
331
|
-
end
|
332
|
-
|
333
|
-
def test_trace_flatten_across_files
|
334
|
-
contents = rotoscope_trace(flatten: true) do
|
335
|
-
foo = FixtureOuter.new
|
336
|
-
foo.do_work
|
337
|
-
end
|
338
|
-
|
339
|
-
assert_equal [
|
340
|
-
{ entity: "FixtureOuter", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
341
|
-
{ entity: "FixtureOuter", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "FixtureOuter", caller_method_name: "new", caller_method_level: "class" },
|
342
|
-
{ entity: "FixtureInner", method_name: "new", method_level: "class", filepath: "/fixture_outer.rb", lineno: -1, caller_entity: "FixtureOuter", caller_method_name: "initialize", caller_method_level: "instance" },
|
343
|
-
{ entity: "FixtureInner", method_name: "initialize", method_level: "instance", filepath: "/fixture_outer.rb", lineno: -1, caller_entity: "FixtureInner", caller_method_name: "new", caller_method_level: "class" },
|
344
|
-
{ entity: "FixtureOuter", method_name: "do_work", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
345
|
-
{ entity: "FixtureInner", method_name: "do_work", method_level: "instance", filepath: "/fixture_outer.rb", lineno: -1, caller_entity: "FixtureOuter", caller_method_name: "do_work", caller_method_level: "instance" },
|
346
|
-
{ entity: "FixtureInner", method_name: "sum", method_level: "instance", filepath: "/fixture_inner.rb", lineno: -1, caller_entity: "FixtureInner", caller_method_name: "do_work", caller_method_level: "instance" }
|
347
|
-
], parse_and_normalize(contents)
|
348
|
-
end
|
349
|
-
|
350
|
-
def test_trace_uses_io_objects
|
351
|
-
string_io = StringIO.new
|
352
|
-
Rotoscope.trace(string_io) do
|
353
|
-
Example.new.normal_method
|
354
|
-
end
|
355
|
-
refute_predicate string_io, :closed?
|
356
|
-
assert_predicate string_io, :eof?
|
357
|
-
contents = string_io.string
|
358
|
-
|
359
|
-
assert_equal [
|
360
|
-
{ event: "call", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
361
|
-
{ event: "call", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
362
|
-
{ event: "return", entity: "Example", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
363
|
-
{ event: "return", entity: "Example", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
364
|
-
{ event: "call", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
365
|
-
{ event: "return", entity: "Example", method_name: "normal_method", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
366
|
-
], parse_and_normalize(contents)
|
367
|
-
|
368
|
-
assert_frames_consistent contents
|
369
|
-
end
|
370
|
-
|
371
|
-
def test_stop_trace_before_start_does_not_raise
|
372
|
-
rs = Rotoscope.new(@logfile)
|
373
|
-
rs.stop_trace
|
374
|
-
end
|
375
|
-
|
376
|
-
def test_gc_rotoscope_without_stop_trace_does_not_crash
|
377
|
-
proc {
|
378
|
-
rs = Rotoscope.new(@logfile)
|
379
|
-
rs.start_trace
|
380
|
-
}.call
|
381
|
-
GC.start
|
382
|
-
end
|
383
|
-
|
384
|
-
def test_gc_rotoscope_without_stop_trace_does_not_break_process_cleanup
|
385
|
-
child_pid = fork do
|
386
|
-
rs = Rotoscope.new(@logfile)
|
387
|
-
rs.start_trace
|
388
|
-
end
|
389
|
-
Process.waitpid(child_pid)
|
390
|
-
assert_equal true, $CHILD_STATUS.success?
|
391
|
-
end
|
392
|
-
|
393
|
-
def test_log_path
|
394
|
-
rs = Rotoscope.new(File.expand_path('tmp/test.csv.gz'))
|
395
|
-
GC.start
|
396
|
-
assert_equal File.expand_path('tmp/test.csv.gz'), rs.log_path
|
397
|
-
end
|
398
|
-
|
399
|
-
def test_ignores_calls_inside_of_threads
|
400
|
-
thread = nil
|
401
|
-
contents = rotoscope_trace do
|
402
|
-
thread = Thread.new { Example.new }
|
403
|
-
end
|
404
|
-
thread.join
|
405
|
-
|
406
|
-
assert_equal [
|
407
|
-
{ event: "call", entity: "Thread", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
408
|
-
{ event: "call", entity: "Thread", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
409
|
-
{ event: "return", entity: "Thread", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
410
|
-
{ event: "return", entity: "Thread", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
411
|
-
], parse_and_normalize(contents)
|
412
|
-
end
|
413
|
-
|
414
|
-
def test_dynamic_class_creation
|
415
|
-
contents = rotoscope_trace { Class.new }
|
416
|
-
|
417
|
-
assert_equal [
|
418
|
-
{ event: "call", entity: "Class", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
419
|
-
{ event: "call", entity: "#<Class:0xXXXXXX>", method_name: "initialize", method_level: "instance", filepath: "/rotoscope_test.rb", lineno: -1 },
|
420
|
-
{ event: "call", entity: "Object", method_name: "inherited", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
421
|
-
{ event: "return", entity: "Object", method_name: "inherited", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
422
|
-
{ event: "return", entity: "#<Class:0xXXXXXX>", method_name: "initialize", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
423
|
-
{ event: "return", entity: "Class", method_name: "new", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 }
|
424
|
-
], parse_and_normalize(contents)
|
425
|
-
end
|
426
|
-
|
427
|
-
def test_dynamic_methods_in_blacklist
|
428
|
-
skip <<-FAILING_TEST_CASE
|
429
|
-
Return events for dynamically created methods (define_method, define_singleton_method)
|
430
|
-
do not have the correct stack frame information (the call of a dynamically defined method
|
431
|
-
is correctly treated as a Ruby :call, but its return must be treated as a :c_return)
|
432
|
-
FAILING_TEST_CASE
|
433
|
-
|
434
|
-
contents = rotoscope_trace(blacklist: [MONADIFY_PATH]) { Example.apply("my value!") }
|
435
|
-
|
436
|
-
assert_equal [
|
437
|
-
{ event: "call", entity: "Example", method_name: "apply", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
438
|
-
{ event: "call", entity: "Example", method_name: "monad", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
439
|
-
{ event: "return", entity: "Example", method_name: "monad", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
440
|
-
{ event: "return", entity: "Example", method_name: "apply", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1 },
|
441
|
-
], parse_and_normalize(contents)
|
442
|
-
end
|
443
|
-
|
444
|
-
def test_flatten_with_dynamic_methods_in_blacklist
|
445
|
-
# the failing test above passes when using `flatten: true` since unmatched stack returns are ignored
|
446
|
-
contents = rotoscope_trace(blacklist: [MONADIFY_PATH], flatten: true) { Example.apply("my value!") }
|
447
|
-
|
448
|
-
assert_equal [
|
449
|
-
{ entity: "Example", method_name: "apply", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "<ROOT>", caller_method_name: "<UNKNOWN>", caller_method_level: "<UNKNOWN>" },
|
450
|
-
{ entity: "Example", method_name: "monad", method_level: "class", filepath: "/rotoscope_test.rb", lineno: -1, caller_entity: "Example", caller_method_name: "apply", caller_method_level: "class" },
|
451
|
-
], parse_and_normalize(contents)
|
452
|
-
end
|
453
|
-
|
454
|
-
private
|
455
|
-
|
456
|
-
def parse_and_normalize(csv_string)
|
457
|
-
CSV.parse(csv_string, headers: true, header_converters: :symbol).map do |row|
|
458
|
-
row = row.to_h
|
459
|
-
row[:lineno] = -1
|
460
|
-
row[:filepath] = row[:filepath].gsub(ROOT_FIXTURE_PATH, '')
|
461
|
-
row[:entity] = row[:entity].gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX")
|
462
|
-
row
|
463
|
-
end
|
464
|
-
end
|
465
|
-
|
466
|
-
def assert_frames_consistent(csv_string)
|
467
|
-
assert_equal csv_string.scan(/\Acall/).size, csv_string.scan(/\Areturn/).size
|
468
|
-
end
|
469
|
-
|
470
|
-
def rotoscope_trace(blacklist: [], flatten: false)
|
471
|
-
Rotoscope.trace(@logfile, blacklist: blacklist, flatten: flatten) { |rotoscope| yield rotoscope }
|
472
|
-
File.read(@logfile)
|
473
|
-
end
|
474
|
-
|
475
|
-
def unzip(path)
|
476
|
-
File.open(path) { |f| Zlib::GzipReader.new(f).read }
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
# https://github.com/seattlerb/minitest/pull/683 needed to use
|
481
|
-
# autorun without affecting the exit status of forked processes
|
482
|
-
Minitest.run(ARGV)
|