jsinstrument 0.0.10 → 0.0.11
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.
- data/lib/jsinstrument/inserting.js +67 -24
- data/lib/jsinstrument/instrumenter.rb +34 -17
- data/lib/jsinstrument/version.rb +1 -1
- metadata +2 -2
@@ -6,34 +6,70 @@
|
|
6
6
|
!function(root){
|
7
7
|
if (root && (typeof root.%{js_object_name} === 'undefined')) {
|
8
8
|
root.%{js_object_name} = {
|
9
|
+
/**
|
10
|
+
* Const for coverage data types
|
11
|
+
*/
|
12
|
+
TYPES: ['line', 'func', 'branch'],
|
9
13
|
/**
|
10
14
|
* Coverage data
|
15
|
+
* data = {
|
16
|
+
* filename: {
|
17
|
+
* line: [lines],
|
18
|
+
* func: [lines],
|
19
|
+
* branch: [lines]
|
20
|
+
* }
|
21
|
+
* }
|
11
22
|
*/
|
12
|
-
|
23
|
+
data: {},
|
13
24
|
/**
|
14
25
|
* register instrumented lines for the file
|
15
26
|
*/
|
16
|
-
register: function(file, lines) {
|
27
|
+
register: function(file, lines, func_lines) {
|
17
28
|
// replace the dot in the filename by underscore to be competible with mongodb
|
18
29
|
file = file.replace(/\./g, '_')
|
19
30
|
// can't register twice for one file
|
20
|
-
if(!this.
|
21
|
-
this.
|
31
|
+
if(!this.data[file]) {
|
32
|
+
this.data[file] = {
|
33
|
+
line: [],
|
34
|
+
func: [],
|
35
|
+
branch: []
|
36
|
+
};
|
22
37
|
for (var i in lines) {
|
23
|
-
this.
|
38
|
+
this.data[file].line[lines[i]] = 0;
|
39
|
+
}
|
40
|
+
for (var i in func_lines) {
|
41
|
+
this.data[file].func[func_lines[i]] = 0;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
},
|
45
|
+
/**
|
46
|
+
* Hit a data
|
47
|
+
*/
|
48
|
+
_hit: function(type, file, line) {
|
49
|
+
if (file && (this.TYPES.indexOf(type) !== -1)) {
|
50
|
+
file = file.replace(/\./g, '_');
|
51
|
+
if (this.data[file] && this.data[file][type]) {
|
52
|
+
this.data[file][type][line] = (this.data[file][type][line]) ? (this.data[file][type][line] + 1) : 1;
|
24
53
|
}
|
25
54
|
}
|
26
55
|
},
|
27
56
|
/**
|
28
57
|
* Hit a line
|
29
58
|
*/
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
59
|
+
hit_line: function(file, line) {
|
60
|
+
this._hit('line', file, line);
|
61
|
+
},
|
62
|
+
/**
|
63
|
+
* Hit a func
|
64
|
+
*/
|
65
|
+
hit_func: function(file, line) {
|
66
|
+
this._hit('func', file, line);
|
67
|
+
},
|
68
|
+
/**
|
69
|
+
* Hit a branch
|
70
|
+
*/
|
71
|
+
hit_branch: function(file, line) {
|
72
|
+
this._hit('branch', file, line);
|
37
73
|
},
|
38
74
|
/**
|
39
75
|
* Upload coverage data to server
|
@@ -46,7 +82,7 @@
|
|
46
82
|
this._uploading = true;
|
47
83
|
|
48
84
|
try {
|
49
|
-
$.post('%{upload_url}', this._serialize(
|
85
|
+
$.post('%{upload_url}', this._serialize(mark)).done(function() {
|
50
86
|
console.log('Coverage data uploaded!');
|
51
87
|
}).always(function() {
|
52
88
|
self._uploading = false;
|
@@ -58,23 +94,30 @@
|
|
58
94
|
/**
|
59
95
|
* serialize data for data uploading
|
60
96
|
*/
|
61
|
-
_serialize: function(
|
97
|
+
_serialize: function(mark) {
|
98
|
+
var data = this.data;
|
62
99
|
var json = [];
|
63
100
|
|
64
101
|
for (var file in data) {
|
65
|
-
var
|
102
|
+
var file_json = [];
|
103
|
+
|
104
|
+
for (var i in TYPES) {
|
105
|
+
var type = TYPES[i];
|
106
|
+
var type_coverage = data[file][type];
|
66
107
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
108
|
+
var array = [];
|
109
|
+
var length = type_coverage.length;
|
110
|
+
for (var line = 0; line < length; line++) {
|
111
|
+
var value = type_coverage[line];
|
112
|
+
if (value === undefined || value === null) {
|
113
|
+
value = '';
|
114
|
+
}
|
115
|
+
array.push(value);
|
73
116
|
}
|
74
|
-
|
117
|
+
file_json.push(this._quote(type) + ':[' + array.join(',') + ']');
|
75
118
|
}
|
76
119
|
|
77
|
-
json.push(this._quote(file) + ':
|
120
|
+
json.push(this._quote(file) + ':{' + file_json.join(',') + '}');
|
78
121
|
}
|
79
122
|
|
80
123
|
var result = '{' + json.join(',') + '}';
|
@@ -119,7 +162,7 @@
|
|
119
162
|
}
|
120
163
|
|
121
164
|
// register the instrumented lines for current file
|
122
|
-
root.%{js_object_name}.register('%{src_filename}', %{instrumented_lines});
|
165
|
+
root.%{js_object_name}.register('%{src_filename}', %{instrumented_lines}, %{instrumented_func_lines});
|
123
166
|
}(this);
|
124
167
|
|
125
168
|
|
@@ -22,7 +22,7 @@ module JSInstrument
|
|
22
22
|
self.src_filename = filename
|
23
23
|
ast = RKelly::Parser.new.parse src
|
24
24
|
raise 'Parse source failed.' unless ast
|
25
|
-
ast, instrumented_lines = instrument_ast ast
|
25
|
+
ast, instrumented_lines, instrumented_func_lines = instrument_ast ast
|
26
26
|
instrumented_src = ast.to_ecma
|
27
27
|
|
28
28
|
inserting = File.open(File.dirname(__FILE__) + '/inserting.js').read
|
@@ -35,7 +35,8 @@ module JSInstrument
|
|
35
35
|
commit_hash: self.commit_hash,
|
36
36
|
batch_text: self.batch_text,
|
37
37
|
data_compress_method: self.data_compress_method,
|
38
|
-
instrumented_lines: instrumented_lines
|
38
|
+
instrumented_lines: instrumented_lines,
|
39
|
+
instrumented_func_lines: instrumented_func_lines
|
39
40
|
}
|
40
41
|
|
41
42
|
(inserting % bindings) + instrumented_src
|
@@ -46,12 +47,16 @@ module JSInstrument
|
|
46
47
|
#
|
47
48
|
ast = RKelly::Visitors::ParentBuilder.new.build ast
|
48
49
|
instrumented_lines = Set.new
|
50
|
+
instrumented_func_lines = Set.new
|
49
51
|
ast.each do |node|
|
50
52
|
parent = node.parent
|
51
53
|
line = node.line
|
52
54
|
node_classname = node.class.name.split(/::/)[-1].sub('Node', '')
|
53
55
|
parent_classname = parent.class.name.split(/::/)[-1].sub('Node', '')
|
56
|
+
|
54
57
|
# instrument only if we can get the line no. and we haven't instrumented it
|
58
|
+
|
59
|
+
# line coverage
|
55
60
|
#
|
56
61
|
if line and not instrumented_lines.member? line
|
57
62
|
if ['ExpressionStatement', 'EmptyStatement', 'DoWhile', 'While', 'For', 'ForIn', 'Continue',
|
@@ -60,7 +65,7 @@ module JSInstrument
|
|
60
65
|
if 'DoWhile' == parent_classname
|
61
66
|
if parent.left.eql? node
|
62
67
|
instrumented_lines.add line
|
63
|
-
parent.left =
|
68
|
+
parent.left = get_hitline_call_block node
|
64
69
|
end
|
65
70
|
# in RKelly, ConditionalNode extends IfNode
|
66
71
|
# which is so annoying
|
@@ -68,39 +73,45 @@ module JSInstrument
|
|
68
73
|
elsif ['If', 'While', 'For', 'ForIn', 'With'].index parent_classname
|
69
74
|
if parent.value.eql? node
|
70
75
|
instrumented_lines.add line
|
71
|
-
parent.value =
|
76
|
+
parent.value = get_hitline_call_block node
|
72
77
|
elsif parent.else.eql? node
|
73
78
|
instrumented_lines.add line
|
74
|
-
parent.else =
|
79
|
+
parent.else = get_hitline_call_block node
|
75
80
|
end
|
76
81
|
elsif ['CaseBlock', 'Label'].index parent_classname
|
77
82
|
# do nothing here
|
78
83
|
elsif 'SourceElements' == parent_classname
|
79
|
-
if
|
84
|
+
if insert_hitline_before node
|
80
85
|
instrumented_lines.add line
|
81
86
|
end
|
82
87
|
end
|
83
88
|
elsif ['With', 'Try'].index node_classname
|
84
89
|
if 'SourceElements' == parent_classname
|
85
|
-
if
|
90
|
+
if insert_hitline_before node
|
86
91
|
instrumented_lines.add line
|
87
92
|
end
|
88
93
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
94
|
+
end
|
95
|
+
end
|
96
|
+
# function coverage
|
97
|
+
#
|
98
|
+
if line and not instrumented_func_lines.member? line
|
99
|
+
if ['FunctionDecl', 'FunctionExpr'].index node_classname
|
100
|
+
if node.function_body
|
101
|
+
insert_hitfunc_in node.function_body, line
|
102
|
+
instrumented_func_lines.add line
|
92
103
|
end
|
93
104
|
end
|
94
105
|
end
|
95
106
|
end
|
96
|
-
[ast, instrumented_lines.sort]
|
107
|
+
[ast, instrumented_lines.sort, instrumented_func_lines.sort]
|
97
108
|
end
|
98
109
|
|
99
110
|
private
|
100
|
-
def
|
111
|
+
def get_hit_call line, func
|
101
112
|
ExpressionStatementNode.new(
|
102
113
|
FunctionCallNode.new(
|
103
|
-
ResolveNode.new("#{self.js_object_name}
|
114
|
+
ResolveNode.new("#{self.js_object_name}.#{func}"),
|
104
115
|
ArgumentsNode.new([
|
105
116
|
StringNode.new("\"#{self.src_filename}\""),
|
106
117
|
NumberNode.new(line)
|
@@ -109,16 +120,16 @@ module JSInstrument
|
|
109
120
|
)
|
110
121
|
end
|
111
122
|
|
112
|
-
def
|
123
|
+
def get_hitline_call_block node
|
113
124
|
BlockNode.new(
|
114
125
|
SourceElementsNode.new([
|
115
|
-
|
126
|
+
get_hit_call(node.line, "hit_line"),
|
116
127
|
node
|
117
128
|
])
|
118
129
|
)
|
119
130
|
end
|
120
131
|
|
121
|
-
def
|
132
|
+
def insert_hitline_before node
|
122
133
|
# get the original node line
|
123
134
|
#
|
124
135
|
line = node.line
|
@@ -131,9 +142,15 @@ module JSInstrument
|
|
131
142
|
false
|
132
143
|
else
|
133
144
|
index = node.parent.value.index{|x| x.eql? node}
|
134
|
-
node.parent.value.insert index,
|
145
|
+
node.parent.value.insert index, get_hit_call(line, "hit_line")
|
135
146
|
true
|
136
147
|
end
|
137
148
|
end
|
149
|
+
|
150
|
+
def insert_hitfunc_in function_body_node, line
|
151
|
+
# FunctionBody.value(SourceElement).value(array).unshift hit_func
|
152
|
+
function_body_node.value.value.unshift get_hit_call(line, "hit_func")
|
153
|
+
end
|
154
|
+
|
138
155
|
end
|
139
156
|
end
|
data/lib/jsinstrument/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsinstrument
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rkelly
|