1
Description
The coverage langlet module is langlet created for code coverage
purposes. The basic idea of the coverage langlet is to compile a
function call into each code block of the analyzed module. If the code
block is entered the function will be called and the call will be
notified. This differs from approaches used by the popular coverage.py
module of Ned Batchelder who uses Pythons builtin tracing function
sys.settrace.
1.1 Terminology
For each code block a Sensor object
will be created and inserted into the block. You can
imagine a
bunch of sensors spreaded all over the code-blocks and signaling their
presence to an external Monitor
object. The Monitor holds a
reference to each sensor and
draws an
image of their activation after execution of the analyzed module.
The ratio between all sensors distributed over the code against those
that were activated
is a measure of code coverage. Currently only statement coverage is
implemented. It remains however an important incentive to advance
beyond statement coverage by using code transformations - the proper
domain of EasyExtend.
2. Use
usage: python fiber.py
[option] ... file
Options:
-o FILE : redirect output from stdout into report output FILE.
-p : pattern used to describe names of
modules imported
using the
coverage
importer. pattern is a
quoted regular expression.
-d : deactivate default pattern ( see
explanation below )
-e
: erase all pycv files in the directory of the
main module and below
file : script file to
start with
The -p option defines a selection among modules using a
regular expression. As default pattern the expression '(?P<test>test\_(?P<mod_name>\w+))'
is used. This pattern
extracts the group of strings
("test_module", "module") from the string "test_module" where "module"
is a module name. It can be deactivated using the -d
option.
Examples:
(1) python run_coverage.py test\test_demo.py
(2) python
run_coverage.py -d language.py
In (1) the module test_all.py will be covered but also
each module test_xxx.py that is imported
during execution of test_all.py as well as each module
xxx.py.
In (2) we deactivate the default import rules of (1) and cover
language.py. The
language module imports the eetransformer module that will be covered
as well.
3 Statement tests
3.1 Symbols
">"
-- marks a location where a sensor
has been inserted
"!" -- marks
a location where a sensor did not respond
3.2 Omissions
The following example shows the result of executing the command python
run_coverage.py
test_demo.py.
Each new codeblock is marked by a sensor. One
exception is made with blocks
if __name__ ==
'__main__':
BLOCK
not being in the __main__ module. They will never get called and the
ratio between
activated/deactivated sensors does not
provide valuable information.
Each measurement on a module is terminated by a status message. If more
than one module is involved a summary is provided.
_____
/ __ \
| / \/ _____ _____ _ __ __ _
__ _ ___
| | / _ \ \ / / _ \ '__/ _` |/ _`
|/ _ \
| \__/\ (_) \ V / __/ | | (_| | (_| | __/
\____/\___/ \_/ \___|_| \__,_|\__, |\___|
__/ |
|___/
----------------------------------------------------------.
Coverage : c:\Python24\Fibers\pytools\test\test_demo.py |
---------------------------------------------------------------------------------------.
0
1 from demo import Demo
2
3
4 > if __name__ == '__main__':
5
Demo(0,-1)
6
d = Demo(1,0)
7 > ! if
0:
# this sensor does nothing for obvious reasons
8
d.f()
---------------------------------------------------------.
Status:
|
2 sensors
created
|
1 sensors did not
respond
|
Coverage: 50%
|
---------------------------------------------------------------------------------------'
-----------------------------------------------------.
Coverage : c:\Python24\Fibers\pytools\test\demo.py |
---------------------------------------------------------------------------------------.
00
01 > class Demo:
02 > def
__init__(self,a,b):
03
>
if a or not b:
04
print "Demo Result => a +:",a
05
>
else:
06
print "Demo Result => a -:",a
07
>
if b<0:
08
>
while 1:
09 >
!
if b<-1:
10
return
11
b+=1
12
>
if b==0:
13
break
14
a-5 # ...does not detect all
unreachables!
15 >
!
b-2 #
may not be reached
16
>
else:
17
print "Demo Result => b:",b
18
19 > ! def f(self):
20
return 0
21
22
23 if __name__ ==
'__main__':
24
Demo(0,-1)
25
d = Demo(1,0)
26
if 0:
27
d.f()
----------------------------------------------------.
Status:
|
10 sensors
created
|
3 sensors did not
respond
|
Coverage:
70%
|
---------------------------------------------------------------------------------------'
========================================================================================
Summary:
12 sensors created
4 sensors did not respond
Coverage: 75%
========================================================================================
4 Expression coverage
4.1 Symbols
">"
-- marks a location where a sensor
has been inserted
"!" -- marks
a location in an expression where a sensor did not respond
"+" -- marks
a location in an expression where a sensor responded
4.2 Coverage of boolean operations
With statement coverage we do not cover boolean operations. Let's
modify the __init__ method of the Demo class in the
following
way:
07
if b<0 or a+b>7:
08
x = 0
09
y = 9
10
else:
11
print b
With statement coverage we do not know which branch of the condition is
executed. If b<0 is always true for any test the alternative branch
defined by
a+b>7 will never be checked.
We can wrap a sensor around any of the conditionals. The idea is to use
an identity function with a side effect:
def measure( expr ):
monitor.send(sensor_id)
return expr
4.1 Notation
If the second condition in the or-test is never activated but the first
one following pattern will be displayed
07
> [+!] if b<0 or a+b>7:
08
x = 0
09
y = 9
10 > ! else:
11
print b
|