aboutsummaryrefslogtreecommitdiffstats
path: root/lib/tools/doc/src/cover.xml
blob: be0fd5bd47862ca69ceb5e57c6afeabeae5f737e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">

<erlref>
  <header>
    <copyright>
      <year>2001</year>
      <year>2012</year>
      <holder>Ericsson AB, All Rights Reserved</holder>
    </copyright>
    <legalnotice>
  The contents of this file are subject to the Erlang Public License,
  Version 1.1, (the "License"); you may not use this file except in
  compliance with the License. You should have received a copy of the
  Erlang Public License along with this software. If not, it can be
  retrieved online at http://www.erlang.org/.

  Software distributed under the License is distributed on an "AS IS"
  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  the License for the specific language governing rights and limitations
  under the License.

  The Initial Developer of the Original Code is Ericsson AB.
    </legalnotice>

    <title>cover</title>
    <prepared></prepared>
    <docno></docno>
    <date></date>
    <rev></rev>
  </header>
  <module>cover</module>
  <modulesummary>A Coverage Analysis Tool for Erlang</modulesummary>
  <description>
    <p>The module <c>cover</c> provides a set of functions for coverage
      analysis of Erlang programs, counting how many times each
      <em>executable line</em> of code is executed when a program is run.      <br></br>

      An executable line contains an Erlang expression such as a matching
      or a function call. A blank line or a line containing a comment,
      function head or pattern in a <c>case</c>- or <c>receive</c> statement
      is not executable.</p>
    <p>Coverage analysis can be used to verify test cases, making sure all
      relevant code is covered, and may also be helpful when looking for
      bottlenecks in the code.</p>
    <p>Before any analysis can take place, the involved modules must be
      <em>Cover compiled</em>. This means that some extra information is
      added to the module before it is compiled into a binary which then
      is loaded. The source file of the module is not affected and no
      <c>.beam</c> file is created.</p>
    <p>Each time a function in a Cover compiled module is called,
      information about the call is added to an internal database of Cover.
      The coverage analysis is performed by examining the contents of
      the Cover database. The output <c>Answer</c> is determined by two
      parameters, <c>Level</c> and <c>Analysis</c>.</p>
    <list type="bulleted">
      <item>
        <p><c>Level = module</c></p>
        <p><c>Answer = {Module,Value}</c>, where <c>Module</c> is the module
          name.</p>
      </item>
      <item>
        <p><c>Level = function</c></p>
        <p><c>Answer = [{Function,Value}]</c>, one tuple for each function in
          the module. A function is specified by its module name <c>M</c>,
          function name <c>F</c> and arity <c>A</c> as a tuple
          <c>{M,F,A}</c>.</p>
      </item>
      <item>
        <p><c>Level = clause</c></p>
        <p><c>Answer = [{Clause,Value}]</c>, one tuple for each clause in
          the module. A clause is specified by its module name <c>M</c>,
          function name <c>F</c>, arity <c>A</c> and position in the function
          definition <c>C</c> as a tuple <c>{M,F,A,C}</c>.</p>
      </item>
      <item>
        <p><c>Level = line</c></p>
        <p><c>Answer = [{Line,Value}]</c>, one tuple for each executable
          line in the module. A line is specified by its module name <c>M</c>
          and line number in the source file <c>N</c> as a tuple
          <c>{M,N}</c>.</p>
      </item>
      <item>
        <p><c>Analysis = coverage</c></p>
        <p><c>Value = {Cov,NotCov}</c> where <c>Cov</c> is the number of
          executable lines in the module, function, clause or line that have
          been executed at least once and <c>NotCov</c> is the number of
          executable lines that have not been executed.</p>
      </item>
      <item>
        <p><c>Analysis = calls</c></p>
        <p><c>Value = Calls</c> which is the number of times the module,
          function, or clause has been called. In the case of line level
          analysis, <c>Calls</c> is the number of times the line has been
          executed.</p>
      </item>
    </list>
    <p><em>Distribution</em></p>
    <p>Cover can be used in a distributed Erlang system. One of the
      nodes in the system must then be selected as the <em>main node</em>, and all Cover commands must be executed from this
      node. The error reason <c>not_main_node</c> is returned if an
      interface function is called on one of the remote nodes.</p>
    <p>Use <c>cover:start/1</c> and <c>cover:stop/1</c> to add or
      remove nodes. The same Cover compiled code will be loaded on each
      node, and analysis will collect and sum up coverage data results
      from all nodes.</p>
    <p>To only collect data from remote nodes without stopping
      <c>cover</c> on those nodes, use <c>cover:flush/1</c></p>
  </description>
  <funcs>
    <func>
      <name>start() -> {ok,Pid} | {error,Reason}</name>
      <fsummary>Start Cover.</fsummary>
      <type>
        <v>Pid = pid()</v>
        <v>Reason = {already_started,Pid}</v>
      </type>
      <desc>
        <p>Starts the Cover server which owns the Cover internal database.
          This function is called automatically by the other functions in
          the module.</p>
      </desc>
    </func>
    <func>
      <name>start(Nodes) -> {ok,StartedNodes} | {error,not_main_node}</name>
      <fsummary>Start Cover on remote nodes.</fsummary>
      <type>
        <v>Nodes = StartedNodes = [atom()]</v>
      </type>
      <desc>
        <p>Starts a Cover server on the each of given nodes, and loads
          all cover compiled modules.</p>
      </desc>
    </func>
    <func>
      <name>compile(ModFile) -> Result</name>
      <name>compile(ModFile, Options) -> Result</name>
      <name>compile_module(ModFile) -> Result</name>
      <name>compile_module(ModFile, Options) -> Result</name>
      <fsummary>Compile a module for Cover analysis.</fsummary>
      <type>
        <v>ModFile = Module | File</v>
        <v>&nbsp;Module = atom()</v>
        <v>&nbsp;File = string()</v>
        <v>Options = [Option]</v>
        <v>&nbsp;Option = {i,Dir} | {d,Macro} | {d,Macro,Value}</v>
        <d>See <c>compile:file/2.</c></d>
        <v>Result = {ok,Module} | {error,File} | {error,not_main_node}</v>
      </type>
      <desc>
        <p>Compiles a module for Cover analysis. The module is given by its
          module name <c>Module</c> or by its file name <c>File</c>.
          The <c>.erl</c> extension may be omitted. If the module is
          located in another directory, the path has to be specified.</p>
        <p><c>Options</c> is a list of compiler options which defaults to
          <c>[]</c>. Only options defining include file directories and
          macros are passed to <c>compile:file/2</c>, everything else is
          ignored.</p>
        <p>If the module is successfully Cover compiled, the function
          returns <c>{ok,Module}</c>. Otherwise the function returns
          <c>{error,File}</c>. Errors and warnings are printed as they
          occur.</p>
        <p>Note that the internal database is (re-)initiated during
          the compilation, meaning any previously collected coverage data
          for the module will be lost.</p>
      </desc>
    </func>
    <func>
      <name>compile_directory() -> [Result] | {error,Reason}</name>
      <name>compile_directory(Dir) -> [Result] | {error,Reason}</name>
      <name>compile_directory(Dir, Options) -> [Result] | {error,Reason}</name>
      <fsummary>Compile all modules in a directory for Cover analysis.</fsummary>
      <type>
        <v>Dir = string()</v>
        <v>Options = [Option]</v>
        <d>See <c>compile_module/1,2</c></d>
        <v>Result = {ok,Module} | {error,File} | {error,not_main_node}</v>
        <d>See <c>compile_module/1,2</c></d>
        <v>Reason = eacces | enoent</v>
      </type>
      <desc>
        <p>Compiles all modules (<c>.erl</c> files) in a directory
          <c>Dir</c> for Cover analysis the same way as
          <c>compile_module/1,2</c> and returns a list with the return
          values.</p>
        <p><c>Dir</c> defaults to the current working directory.</p>
        <p>The function returns <c>{error,eacces}</c> if the directory is not
          readable or <c>{error,enoent}</c> if the directory does not exist.</p>
      </desc>
    </func>
    <func>
      <name>compile_beam(ModFile) -> Result</name>
      <fsummary>Compile a module for Cover analysis, using an existing beam.</fsummary>
      <type>
        <v>ModFile = Module | BeamFile</v>
        <v>&nbsp;Module = atom()</v>
        <v>&nbsp;BeamFile = string()</v>
        <v>Result = {ok,Module} | {error,BeamFile} | {error,Reason}</v>
        <v>&nbsp;Reason = non_existing | {no_abstract_code,BeamFile} | {encrypted_abstract_code,BeamFile} | {already_cover_compiled,no_beam_found,Module} | not_main_node</v>
      </type>
      <desc>
        <p>Does the same as <c>compile/1,2</c>, but uses an existing
          <c>.beam</c> file as base, i.e. the module is not compiled
          from source. Thus <c>compile_beam/1</c> is faster than
          <c>compile/1,2</c>.</p>
        <p>Note that the existing <c>.beam</c> file must contain
          <em>abstract code</em>, i.e. it must have been compiled with
          the <c>debug_info</c> option. If not, the error reason
          <c>{no_abstract_code,BeamFile}</c> is returned.
          If the abstract code is encrypted, and no key is available
          for decrypting it, the error reason 
          <c><![CDATA[{encrypted_abstract_code,BeamFile} is returned. <p>If only the module name (i.e. not the full name of the <c>.beam]]></c> file) is given to this function, the
          <c>.beam</c> file is found by calling
          <c>code:which(Module)</c>. If no <c>.beam</c> file is found,
          the error reason <c>non_existing</c> is returned. If the
          module is already cover compiled with <c>compile_beam/1</c>,
          the <c>.beam</c> file will be picked from the same location
          as the first time it was compiled. If the module is already
          cover compiled with <c>compile/1,2</c>, there is no way to
          find the correct <c>.beam</c> file, so the error reason
          <c>{already_cover_compiled,no_beam_found,Module}</c> is
          returned.</p>
        <p><c>{error,BeamFile}</c> is returned if the compiled code
          can not be loaded on the node.</p>
      </desc>
    </func>
    <func>
      <name>compile_beam_directory() -> [Result] | {error,Reason}</name>
      <name>compile_beam_directory(Dir) -> [Result] | {error,Reason}</name>
      <fsummary>Compile all .beam files in a directory for Cover analysis.</fsummary>
      <type>
        <v>Dir = string()</v>
        <v>Result = See compile_beam/1</v>
        <v>Reason = eacces | enoent</v>
      </type>
      <desc>
        <p>Compiles all modules (<c>.beam</c> files) in a directory
          <c>Dir</c> for Cover analysis the same way as
          <c>compile_beam/1</c> and returns a list with the return
          values.</p>
        <p><c>Dir</c> defaults to the current working directory.</p>
        <p>The function returns <c>{error,eacces}</c> if the directory is not
          readable or <c>{error,enoent}</c> if the directory does not exist.</p>
      </desc>
    </func>
    <func>
      <name>analyse(Module) -> {ok,Answer} | {error,Error}</name>
      <name>analyse(Module, Analysis) -> {ok,Answer} | {error,Error}</name>
      <name>analyse(Module, Level) -> {ok,Answer} | {error,Error}</name>
      <name>analyse(Module, Analysis, Level) -> {ok,Answer} | {error,Error}</name>
      <fsummary>Analyse a Cover compiled module.</fsummary>
      <type>
        <v>Module = atom()</v>
        <v>Analysis = coverage | calls</v>
        <v>Level = line | clause | function | module</v>
        <v>Answer = {Module,Value} | [{Item,Value}]</v>
        <v>&nbsp;Item = Line | Clause | Function</v>
        <v>&nbsp;&nbsp;Line = {M,N}</v>
        <v>&nbsp;&nbsp;Clause = {M,F,A,C}</v>
        <v>&nbsp;&nbsp;Function = {M,F,A}</v>
        <v>&nbsp;&nbsp;&nbsp;M = F = atom()</v>
        <v>&nbsp;&nbsp;&nbsp;N = A = C = integer()</v>
        <v>&nbsp;Value = {Cov,NotCov} | Calls</v>
        <v>&nbsp;&nbsp;Cov = NotCov = Calls = integer()</v>
        <v>Error = {not_cover_compiled,Module} | not_main_node</v>
      </type>
      <desc>
        <p>Performs analysis of a Cover compiled module <c>Module</c>, as
          specified by <c>Analysis</c> and <c>Level</c> (see above), by
          examining the contents of the internal database.</p>
        <p><c>Analysis</c> defaults to <c>coverage</c> and <c>Level</c>
          defaults to <c>function</c>.</p>
        <p>If <c>Module</c> is not Cover compiled, the function returns
          <c>{error,{not_cover_compiled,Module}}</c>.</p>
	<p>HINT: It is possible to issue multiple analyse_to_file commands at
	  the same time. </p>
      </desc>
    </func>
    <func>
      <name>analyse_to_file(Module) -> </name>
      <name>analyse_to_file(Module,Options) -> </name>
      <name>analyse_to_file(Module, OutFile) -> </name>
      <name>analyse_to_file(Module, OutFile, Options) ->  {ok,OutFile} | {error,Error}</name>
      <fsummary>Detailed coverage analysis of a Cover compiled module.</fsummary>
      <type>
        <v>Module = atom()</v>
        <v>OutFile = string()</v>
        <v>Options = [Option]</v>
        <v>Option = html</v>
        <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | no_source_code_found | not_main_node</v>
        <v>&nbsp;File = string()</v>
        <v>&nbsp;Reason = term()</v>
      </type>
      <desc>
        <p>Makes a copy <c>OutFile</c> of the source file for a module
          <c>Module</c>, where it for each executable line is specified
          how many times it has been executed.</p>
        <p>The output file <c>OutFile</c> defaults to
          <c>Module.COVER.out</c>, or <c>Module.COVER.html</c> if the
          option <c>html</c> was used.</p>
        <p>If <c>Module</c> is not Cover compiled, the function returns
          <c>{error,{not_cover_compiled,Module}}</c>.</p>
        <p>If the source file and/or the output file cannot be opened using
          <c>file:open/2</c>, the function returns
          <c>{error,{file,File,Reason}}</c> where <c>File</c> is the file
          name and <c>Reason</c> is the error reason.</p>
        <p>If the module was cover compiled from the <c>.beam</c>
          file, i.e. using <c>compile_beam/1</c> or
          <c>compile_beam_directory/0,1</c>, it is assumed that the
          source code can be found in the same directory as the
          <c>.beam</c> file, or in <c>../src</c> relative to that
          directory. If no source code is found, 
          <c>,{error,no_source_code_found}</c> is returned.</p>
	<p>HINT: It is possible to issue multiple analyse_to_file commands at
	  the same time. </p> 
      </desc>
    </func>
    <func>
      <name>async_analyse_to_file(Module) -> </name>
      <name>async_analyse_to_file(Module,Options) -> </name>
      <name>async_analyse_to_file(Module, OutFile) -> </name>
      <name>async_analyse_to_file(Module, OutFile, Options) ->  pid()</name>
      <fsummary>Asynchronous call to analyse_to_file.</fsummary>
      <type>
        <v>Module = atom()</v>
        <v>OutFile = string()</v>
        <v>Options = [Option]</v>
        <v>Option = html</v>
        <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | no_source_code_found | not_main_node</v>
        <v>&nbsp;File = string()</v>
        <v>&nbsp;Reason = term()</v>
      </type>
      <desc>
	<p>This function works exactly the same way as 
	<seealso marker="#analyse_to_file-1">analyse_to_file</seealso> except
	that it is asynchronous instead of synchronous. The spawned process
	will link with the caller when created. If an <c>Error</c> occurs
	while doing the cover analysis the process will crash with the same
	error reason as <seealso marker="#analyse_to_file-1">analyse_to_file</seealso> 
	would return.</p>
      </desc>
    </func>
    <func>
      <name>modules() -> [Module] | {error,not_main_node}</name>
      <fsummary>Return all Cover compiled modules.</fsummary>
      <type>
        <v>Module = atom()</v>
      </type>
      <desc>
        <p>Returns a list with all modules that are currently Cover
          compiled.</p>
      </desc>
    </func>
    <func>
      <name>imported_modules() -> [Module] | {error,not_main_node}</name>
      <fsummary>Return all modules for which there are imported data.</fsummary>
      <type>
        <v>Module = atom()</v>
      </type>
      <desc>
        <p>Returns a list with all modules for which there are
          imported data.</p>
      </desc>
    </func>
    <func>
      <name>imported() -> [File] | {error,not_main_node}</name>
      <fsummary>Return all imported files.</fsummary>
      <type>
        <v>File = string()</v>
      </type>
      <desc>
        <p>Returns a list with all imported files.</p>
      </desc>
    </func>
    <func>
      <name>which_nodes() -> [Node] | {error,not_main_node}</name>
      <fsummary>Return all nodes that are part of the coverage analysis.</fsummary>
      <type>
        <v>Node = atom()</v>
      </type>
      <desc>
        <p>Returns a list with all nodes that are part of the coverage
          analysis. Note that the current node is not returned. This
          node is always part of the analysis.</p>
      </desc>
    </func>
    <func>
      <name>is_compiled(Module) -> {file,File} | false |  {error,not_main_node}</name>
      <fsummary>Check if a module is Cover compiled.</fsummary>
      <type>
        <v>Module = atom()</v>
        <v>Beam = string()</v>
      </type>
      <desc>
        <p>Returns <c>{file,File}</c> if the module <c>Module</c> is
          Cover compiled, or <c>false</c> otherwise. <c>File</c> is
          the <c>.erl</c> file used by <c>cover:compile_module/1,2</c>
          or the <c>.beam</c> file used by <c>compile_beam/1</c>.</p>
      </desc>
    </func>
    <func>
      <name>reset(Module) -></name>
      <name>reset() ->  ok | {error,not_main_node}</name>
      <fsummary>Reset coverage data for Cover compiled modules.</fsummary>
      <type>
        <v>Module = atom()</v>
      </type>
      <desc>
        <p>Resets all coverage data for a Cover compiled module
          <c>Module</c> in the Cover database on all nodes. If the
          argument is omitted, the coverage data will be reset for all
          modules known by Cover.</p>
        <p>If <c>Module</c> is not Cover compiled, the function returns
          <c>{error,{not_cover_compiled,Module}}</c>.</p>
      </desc>
    </func>
    <func>
      <name>export(ExportFile)</name>
      <name>export(ExportFile,Module) -> ok | {error,Reason}</name>
      <fsummary>Reset coverage data for Cover compiled modules.</fsummary>
      <type>
        <v>ExportFile = string()</v>
        <v>Module = atom()</v>
        <v>Reason = {not_cover_compiled,Module} | {cant_open_file,ExportFile,Reason} | not_main_node</v>
      </type>
      <desc>
        <p>Exports the current coverage data for <c>Module</c> to the
          file <c>ExportFile</c>. It is recommended to name the
          <c>ExportFile</c> with the extension <c>.coverdata</c>, since
          other filenames can not be read by the web based interface to
          cover.</p>
        <p>If <c>Module</c> is not given, data for all Cover compiled
          or earlier imported modules is exported.</p>
        <p>This function is useful if coverage data from different
          systems is to be merged.</p>
        <p>See also <c>cover:import/1</c></p>
      </desc>
    </func>
    <func>
      <name>import(ExportFile) -> ok | {error,Reason}</name>
      <fsummary>Reset coverage data for Cover compiled modules.</fsummary>
      <type>
        <v>ExportFile = string()</v>
        <v>Reason = {cant_open_file,ExportFile,Reason} | not_main_node</v>
      </type>
      <desc>
        <p>Imports coverage data from the file <c>ExportFile</c>
          created with <c>cover:export/1,2</c>. Any analysis performed
          after this will include the imported data.</p>
        <p>Note that when compiling a module <em>all existing coverage data is removed</em>, including imported data. If a module is
          already compiled when data is imported, the imported data is
          <em>added</em> to the existing coverage data.</p>
        <p>Coverage data from several export files can be imported
          into one system. The coverage data is then added up when
          analysing.</p>
        <p>Coverage data for a module can not be imported from the
          same file twice unless the module is first reset or
          compiled. The check is based on the filename, so you can
          easily fool the system by renaming your export file.</p>
        <p>See also <c>cover:export/1,2</c></p>
      </desc>
    </func>
    <func>
      <name>stop() -> ok | {error,not_main_node}</name>
      <fsummary>Stop Cover.</fsummary>
      <desc>
        <p>Stops the Cover server and unloads all Cover compiled code.</p>
      </desc>
    </func>
    <func>
      <name>stop(Nodes) -> ok | {error,not_main_node}</name>
      <fsummary>Stop Cover on remote nodes.</fsummary>
      <type>
        <v>Nodes = [atom()]</v>
      </type>
      <desc>
        <p>Stops the Cover server and unloads all Cover compiled code
          on the given nodes. Data stored in the Cover database on the
          remote nodes is fetched and stored on the main node.</p>
      </desc>
    </func>
    <func>
      <name>flush(Nodes) -> ok | {error,not_main_node}</name>
      <fsummary>Collect cover data from remote nodes.</fsummary>
      <type>
        <v>Nodes = [atom()]</v>
      </type>
      <desc>
        <p>Fetch data from the Cover database on the remote nodes and
        stored on the main node.</p>
      </desc>
    </func>
  </funcs>

  <section>
    <title>SEE ALSO</title>
    <p>code(3), compile(3)</p>
  </section>
</erlref>