Incremental Testing of Adaptive Software Linda M. Keszenheimer and Karl J. Lieberherr
[email protected],
[email protected] c 1994 by the authors. All rights reserved. Copyright November 29, 1994 Abstract Class evolution can have signi cant impact on the maintenance and testing of an object-oriented application. Adaptive software describes an object-oriented programming model where programs are implemented with the intent of being exible to changes in class structure. A software component is implemented and debugged based on a generic class structure, and subsequently customized in many programs with speci c class structures. Each time an adaptive component is customized with a speci c class structure, the issue of how to test the customization occurs. This paper presents a model for incrementally testing adaptive software during customization, based on initial testing with a representative class structure.
Keywords: Object-Oriented Software Engineering, Software Testing, Software Maintenance, Adaptive Software, Patterns, Class Evolution.
1 Introduction Object-oriented software engineering is being increasingly used for system development, primarily due to advantages gained from reusable components. The majority of research and literature on object-oriented software engineering has focused on analysis, design and implementation; whereas research and experience in maintenance and testing is comparatively lagging. While reuse of components is an assumed bene t of object-oriented software, it is vital that a component be well tested before it is reused. Although a well tested component will still require testing in its new environment, it is desirable to minimize this eort. Class evolution has signi cant impact on the maintenance and testing of an application. While class evolution has been well researched, the focus has been on maintaining the structural consistency of objects existing in 1
a database. The impact of class adaptation on maintenance and testing of behavior remains to be analyzed. Adaptive software [10], [16] refers to a model of software development in which program components are designed to be exible to changes in class structure. Behavior is implemented based on a set of constraints that de ne minimal requirements of class structure. The class constraints de ne a language of compatible customizers , which are speci c class designs. An adaptive component can subsequently be tted into many customizers, thus allowing algorithmic reuse. The adaptive software model has been implemented in Demeter System/C++, a CASE tool for developing object-oriented applications. Each time an adaptive component is customized by a speci c class structure, the issue of how to test the customization occurs. This paper presents a model for incrementally testing adaptive software during customization, based on initial testing with a representative class structure. The representative class structure used for initial testing is the minimal class structure that can adequately unit test the component. When the adaptive component is customized with a speci c class structure, the potential program-based errors which may be introduced can be statically checked. The eort of testing the customization is largely reduced by the initial testing performed on the representative class structure. The organization of this paper is the following. Section 2 provides an introduction to adaptive software, describing the model for de ning class structure and behavior. Section 3 de nes the process for testing adaptive software. Section 4 details related work in testing object-oriented programs during class evolution. Finally, section 5 concludes with future research.
2 Adaptive Software Object-oriented programs are typically developed based on a speci c class structure. A programmer designs a class by specifying its attributes and relations to other classes. Behavior is implemented by attaching functions or methods to the class structure. It is often necessary to have several classes collaborate on a particular task. This is implemented through message passing, where a message is sent along a speci c relation between classes. The class design becomes hard-wired into the methods, using speci c relations among the classes to implement collaboration. When it is necessary to adapt the class structure, the maintainer must modify existing methods to refer to the relations of the new class structure. 2
It is not a trivial task to understand the structure of object-oriented applications [15]. Object-oriented programs tend to consist of large numbers of small methods, with many methods simply propagating a request to another class, potentially passing objects through argument parameters. The program maintainer has to trace potentially long chains of calling and data ow relations. It can be dicult to understand the control and dependence between methods due to dynamic binding, as well as the ow and dependence of objects through method calls. Adaptive software alleviates many of the program understanding and maintenance problems that arise during class evolution. Behavior is de ned in a manner that places minimal assumptions on class structure. The separation of structural de nition from behavioral de nition helps elevate maintainability during structural evolution. The speci cation of a particular task is separated into several components. One component will specify the classes and relations used to collaborate on the task (a propagation graph), another component describes the ow of objects into and out of methods during the collaboration (transportation graphs) and other components (code fragments) describe task speci c behavior aside from the propagation and transportation behavior. Each of these components can be developed and tested separately, and subsequently reused in many dierent tasks. Figure 1 shows the layered architecture of adaptive software components.
2.1 Representing Class Structure The representation used in this paper is based on the Demeter data model[7]. Object structure is described in an Object Graph , where vertices represent objects and edges represent relations between objects. A Class Dictionary Graph describes a speci c class structure, with vertices representing abstract and concrete classes,
and edges representing subclass and part-of relations. A class dictionary graph may be instantiated with many object graphs, and a single object graph may be used to instantiate many class dictionary graphs. Test cases containing object graphs, or their textual equivalent, will be used to test programs. Figure 2 contains two class dictionary graphs and a template graph. A class dictionary graph is considered legal if the inheritance hierarchy is acyclic and if all direct and inherited parts of a class are uniquely labeled and ordered. To simplify the formulas in this paper, single inheritance is assumed. A template graph is used to de ne a set of legal class dictionary graphs for a given software component. The template graph in Figure 2 describes a set of minimalassumptions on class structure for a product ordering system. 3
Task Specification Propagation Patterns
Structural Specification
Object Flow Specification
Transportation Patterns Y 0/n
Y
Y
0/n
Y
Y x001
Y 0/n
XList
Y
x001 Y
Y
Y
Y
XList
rest
x001 XEList
XNEList
Y
XList
Y
Y
XEList rest
Template Graphs
XEList
XNEList
Path Specification
Y
Graph Directives Y Y x001 x001
XList
Y Y
XList
x001
rest x001
XList
rest
XEList
XNEList
XList XNEList
rest
Y rest
x001
XNEList Y XEList
XNEList XList
Y
x001
Y x001
XList
rest x001
XList
Y XNEList
XEList
rest
Y
XList
x001
rest
XNEList x001
XNEList
XEList
XEList
Customization
XList
rest XList XNEList
Class Dictionary Graphs
XEList
rest rest XNEList
XNEList
XEList
XEList
Instantiation Object Graphs
Figure 1: Layered architecture of adaptive software. The template graph describes a set of generic relations between companies, orders, products and customers. A company has many orders placed for products. Each order has associated products and customers. When an order is placed, it is initially un lled and has a due date. When the order is eventually delivered to the customer, it is considered lled. Every product has a code, and each customer has a name. The class dictionary graphs in Figure 2 de ne two speci c class designs that are legal customizations of the template graph. There are several types of vertices and edges in a class dictionary graph. A terminal vertex , drawn as ( ), represents an elementary data structure such as an Ident , String or Real . A construction vertex represents a concrete class, also drawn as (
). The representative class dictionary graph in Figure 2 has construction
vertices Company , Order , Product , Customer , Filled , UnFilled and Date . An alternation vertex (
) represents
an abstract class. FilledStatus is the only alternation vertex in the representative class dictionary graph. A repetition vertex (
) represents a collection class such as a list. The representative class dictionary graph has
three repetition vertices: OrderList , ProductList , and CustomerList . l ) with label l . A construction edge describes the part-of relation and is drawn as a single-line arrow (?!
4
Company
Product code 5 Ident
depts 1
SalesPerson List
3
filledStatus 4
PickUp
Filled
Ident
UnFilled due 7
Order
products 2
Customer name 6
2
OrderList
OrderList
FilledStatus
SalesPerson orders
orders 1
Order 2
Company
Company
1
Product List
Date
3 customer
filledStatus 4 FilledStatus
LineItem List
Customer List
product 6
Customer
code 8
Ident
Template Graph
FilledStatus
Ident
Product Date
Number
Filled
UnFilled due
Ident
Representative Class Dictionary Graph
Delivery filledStatus
9 7 quantity name
due 7
name 6
Ident
UnFilled
5
Customer
LineItem Filled
Product code 5
items Order 3 customer 4
Customizer
10
Date
Figure 2: Example class structures. l w indicates class v has a relation, or part, labeled l to class w . The construction Construction edge v ?!
edges in the representative class dictionary graph are Company orders ?! OrderList, Order products ?! ProductList, Order customer ?! CustomerList, Order
filledStatus
?!
code Ident, Customer name FilledStatus, Product ?! ?! Ident, and
date Date. The construction edges in a class dictionary graph are uniquely ordered. UnFilled ?!
An alternation edge represents the subclass relation, drawn as a double-line arrow (=) ). Alternation edge v =) w indicates v is a superclass of w . Only alternation vertices may have outgoing alternation edges. There are two alternation edges in the representative class dictionary graph, FilledStatus =) Filled and FilledStatus =) UnFilled. The re exive transitive closure of the EA relation is called the alternation-reachable relation, drawn as + )? . If v )? w, then w is reachable from v through a path of zero or more alternation edges, while v ) w implies
v )? w and v 6= w. Finally, a repetition edge v ?! w indicates v is a list containing instances of w. There are three repetition edges in the representative class dictionary graph, OrderList ?! Order, ProductList ?! Product and CustomerList ?! Customer.
De nition 1 A Class Dictionary Graph ? is a directed graph de ned as: ? = (V; ; E; Ord) where: V = VC [VA[VR[VT VC is a nite set of construction vertices VA is a nite set of alternation vertices
5
VR is a nite set of repetition vertices VT is a nite set of terminal vertices
is a nite set of edge labels. E = EC [ EA [ ER EC is a relation on (V C [ V A) V describing the labeled construction edges. EA is a relation on V A (V C [ V A) describing the alternation edges.
ER is a relation on V R V describing repetition edges.
Ord : EC ! N is a function that maps each construction edge to a natural number. Behavior is de ned in an adaptive program by a set of Propagation Patterns [8]. A single propagation pattern describes the collaboration and object ow required to implement a particular task. Propagation patterns can be integrated and reused in many programs. A propagation pattern is developed based on a generic class structure. To actually test a propagation pattern, it must be customized with a speci c class dictionary graph. This allows test cases containing actual object graphs to be developed. The behavior speci ed by the propagation pattern is adapted to t onto the class dictionary graph and code is generated to implement the behavior. After adequate testing using coverage measures based on the customized propagation pattern, the programmer may feel con dent that the propagation pattern has been properly debugged. An issue develops when the propagation pattern is customized by another class dictionary graph, which occurs either when the propagation pattern is used in a dierent program, or when the class structure of a program evolves. When a propagation pattern is tested and debugged with one customizer, there are no assurances that it will work correctly with another. With no restrictions on the structure of customizers, adequate testing coverage of one customizer does not imply adequacy of another. To solve this issue of testing adaptive software, it is necessary to de ne a Template Graph for a set of propagation patterns. This paper introduces the template graph, which speci es a set of class constraints that de ne the legal customizers for a propagation pattern. To reason about a propagation pattern before it has been customized, a representative class dictionary graph is generated from the template graph to be used for testing and debugging.
6
The representative is a minimal class dictionary graph adequate to fully unit test a propagation pattern. The propagation pattern can subsequently be customized by an in nite number of class dictionary graphs that meet the constraints de ned in the template graph. This is in the same fashion as schema and view integration in database applications, where components are developed separately using minimal views of a database, and then integrated and reused in multiple applications [1], [13]. Testing a propagation pattern during customization occurs in an incremental fashion. The majority of errors can be being found using the representative class dictionary graph. As in a class dictionary graph, a template graph contains construction, alternation and terminal vertices as well as construction and alternation edges. There is an additional edge not found in the class dictionary graph
called a template edge . Template edge v ; w indicates class v has a relation to class w . The template graph in Figure 2 has three template edges, Company ; Order, Order ; Product, Order ; Customer.
De nition 2 A Template Graph is a directed graph de ned as: = (V; ; E; Ord) where: V = V C [ V A [ V T , are de ned as in a class dictionary graph is a nite set of edge labels. E = EC [ EA [ ET EC is a relation on (V C [ V A) V describing the labeled construction edges. EA is a relation on V A (V C [ V A) describing the alternation edges. ET is a relation on (V C [ V A) V describing the template edges.
Ord : (EC [ ET) ! N is a function that maps each construction and template edge to a natural number. Template edge v ; w implies a construction edge, a repetition edge, a path (sequence of construction, alternation and repetition edges), or multiple paths between vertices v and w must exist in all legal customizers. The edges in the path must not pass through other vertices contained in the template graph, and must contain at least one construction or repetition edge. A template edge allows algorithms to be written assuming a relation exists between the classes, yet the details of the relation are delayed until customization. Similarly, alternation 7
edge v =) w in a template graph may be replaced in a customizer with a path of alternation edges between v and w . A construction vertex in the template graph can be represented by an alternation vertex with subclasses in the customizer. The ordering of parts (construction and template edges) for a construction vertex v in the template graph must be preserved in the customizer. The Ord function is important since edges for a vertex are traversed in a propagation graph in a speci c order. Figure 2 contains the representative class dictionary graph for describing the product ordering data model. This class dictionary graph is generated from the template graph to serve as a representative class structure used for testing and debugging. The transformation rules for generating the representative class dictionary graph from a template graph are simple to automate, in that each template edge is transformed into a path containing a repetition class. This allows the generic relation in the template graph to be tested with zero or more instances of the target class. A speci c customizer can replace the template edge with any legal sequence of edges. Behavior will be developed and tested using the representative class dictionary graph and subsequent customization can occur with an in nite number of possible class designs, including the customizer shown in Figure 2. Let source(e) and target(e) be two functions which return respectively the source or target vertex for an edge in the graph. To simplify formulas it is assumed that class dictionary graphs have been attened, meaning inherited construction edges are distributed down to subclasses.
De nition 3 A class dictionary graph ? = (V?; ?; E?) is a legal customizer of a template graph
= (V ; ; E ) i:
V A V A? ; V T V T? Each alternation and terminal vertex in the template graph must exist in the customizer.
8v 2 V C : v 2 (V A? [ V C? [ V R?) Each construction vertex in the template graph must exist in the customizer as either a construction, alternation or repetition vertex.
EC EC? Each construction edge in the template graph must exist in the customizer.
8
+ 8(v ) w) 2 EA : v ) w2?
If w is a direct subclass of v in the template graph, w must be a direct or indirect subclass of v in the customizer.
8(v ; w) 2 ET : 9 a path p = e0 e1 : : :en 2 ? where :
{ source(e0 ) = v, target(en ) = w There exists a path of edges from v to w in the customizer.
{ 9i : 0 i n : ei 2 (EC? [ ER?) The path must contain at least one construction or repetition edge.
{ 8i : 1 i < n : target(ei ) 62 (V ) The edges in the path must not pass through other vertices in the template graph.
8ei ; ej 2 (EC [ ET ) such that source(ei ) = source(ej ): if Ord (ei ) < Ord (ej ) then Ord?(ei ) < Ord?(ej ) The ordering of parts for a vertex in the template graph must be preserved in the customizer.
2.2 Representing Behavior In an object-oriented program, behavior is attached to a particular class. Classes often collaborate to implement a task, requiring the propagation of messages and requests along chains of class relations. Objects are often passed as argument parameters during message propagation. Code designed to propagate a message request along a path of class relations can be time consuming to produce and dicult to maintain as class structure evolves. Certain communication paths among classes tend to be reused often, with dierent tasks attaching behavior to various classes along those paths. It is useful to de ne traversal paths among classes and augment them with task speci c code. An adaptive program implements behavior by specifying subgraphs of a class dictionary graph used for collaboration and object ow. A Graph Directive is a speci cation used to describe a subgraph of a template graph or a class dictionary graph, as is shown in Figure 3. A graph directive will specify a source and one or more target vertices, and may specify intermediate vertices and edges to be included or excluded in the subgraph.
9
Graph Directive
SubGraph
Template Graph
Company
Company
FROM Company TO Product
applied to
=
Order
Product code Ident
Customer
Order
Product
name Ident
Figure 3: Applying a graph directive to a template graph. A Propagation Pattern speci es the class collaboration and object ow required to implement a task. They provide a necessary level of abstraction when implementing object behavior to facilitate class evolution [3],[5]. A propagation pattern implements an algorithm based on a generic class structure, and can be customized with speci c class structures in many programs. A propagation pattern consists of a signature, traversal directive, transportation patterns, and code fragments. A Signature speci es the function name, return type and formal arguments. A Traversal Directive speci es a graph directive to be applied to the template graph to de ne a Propagation Graph , which indicates the collaborating classes and relations used to implement the task. A Transportation Pattern describes the ow of an object along the propagation graph, or a subgraph of it. When
one class makes a request of another, it often needs to send information along with the request, or receive information back from the request. A transportation pattern describes object ow by specifying a graph directive to de ne a Transportation Graph . Finally, a Code Fragment describes task-speci c behavior aside from the traversal and transportation behavior. Figure 4 contains several simple propagation patterns for printing information for overdue orders, as well as a template graph de ning constraints for the propagation patterns and graph directives to be used to compute subgraphs of the template graph. Figure 5 shows the propagation and transportation graphs, based on the representative class dictionary graph, and an example of generated C++ code [16] for the overDue propagation pattern. The propagation graph for the overDue propagation pattern is from Company to UnFilled , indicating traversal from each Company object to each UnFilled object within an Order object. The code fragment for UnFilled orders speci es that if today's date is past the due date, then order information will be printed out.
This requires calls to the other propagation patterns, printCust and printProd . The overDue propagation pattern 10
TEMPLATE GRAPH
OPERATION void overDue() TRAVERSE CtoU CARRY IN Order* o=(@this@) ALONG OtoU WRAPPER UnFilled PREFIX (@ if ((*due) < today()) { o−>printCust(); o−>printProd(); due−>g_print(); } @)
CLASSES: Company, Order, Product, Customer, FilledStatus, Filled, Unfilled, Date, Ident EDGES ~>Company, Order //template ~>Order, Product //template ~>Order, Customer //template −>Order, FilledStatus, filledStatus //construction =>FilledStatus, Filled //alternation =>FilledStatus, UnFilled //alternation −>Product, Ident, code //construction −>Customer, Ident, name //construction −>UnFilled, Date, due //construction
OPERATION void printCust() TRAVERSE OtoC WRAPPER Customer PREFIX (@ this−>g_print(); @) OPERATION void printProd() TRAVERSE OtoP WRAPPER Product PREFIX (@ this−>g_print(); @)
DIRECTIVES CtoU= FROM Company TO UnFilled OtoU= FROM Order TO UnFilled OtoP= FROM Order TO Product OtoC = FROM Order TO Customer
Figure 4: Template graph and propagation patterns for printing overdue orders
void Company::overDue() { orders−>overDue(); }
Company orders
void OrderList::overDue() { Order_list_iterator next_Order(*this); Order* each_order; while (each_order = next_Order()) each_order−>overDue(); }
OrderList Order filledStatus
Order
FilledStatus
filledStatus FilledStatus
UnFilled
void Order::overDue() { Order* o = this; filled−>overDue(o); }
UnFilled
Propagation Graph
Transportation Graph
OPERATION void overDue() TRAVERSE CtoU CARRY IN Order* o=(@this@) ALONG OtoU WRAPPER UnFilled PREFIX (@ if ((*due) < today()) { o−>printCust(); o−>printProd(); due−>g_print(); } @)
//virtual void FilledStatus::overDue(Order* o) { } void UnFilled::overDue(Order* o) { if ((*due) < today()) { o−>printCust(); o−>printProd(); due−>g_print(); } Generated Code
Propagation Pattern
Figure 5: Propagation and transportation graphs with generated code
11
has one transportation pattern, which carries an Order object referenced by variable o from the Order vertex to the UnFilled vertex. This allows code in the UnFilled vertex to further propagate messages to the Order object. The other two propagation patterns, printCust and printProd simply traverse from the Order vertex respectively to the Customer and Product vertices, printing information. The propagation patterns are developed based on the class constraints de ned by the template graph in Figure 4, which is a textual description of the template graph of Figure 2. While this example shows all three propagation patterns using the same template graph, it also could have used three separate template graphs, each containing the constraints relevant to a single propagation pattern. Propagation patterns can be tested and debugged before being customized by using the representative class dictionary graph generated from the template graph. To ensure adequate testing, coverage is performed based on control ow, control dependence, data ow and data dependence of the propagation pattern customized by the representative class dictionary graph. The signature of a propagation pattern speci es the function name, return type, formal arguments and an optional expression to initialize the return value. It can be described in a textual form (keywords are uppercased) as: OPERATION returnType functionName()
[ INIT (@ expression @) ]
A traversal directive de nes a propagation graph, and is described in a textual form as: TRAVERSE D
Where D is the name of a graph directive. A graph directive speci es constraints that de ne a subgraph of a template graph or a class dictionary graph, and has the textual form: FROM class [ THROUGH edge-patterns ] [ BYPASSING edge-patterns ] [ VIA class-set ] [ TO class-set ]
The Transportation Pattern TP de nes the transportation of an object during traversal, and is described in a textual form as : CARRY I T n = (@ e1 @) ALONG D AT V n = (@ e2 @)
12
Where I indicates the direction an object ows along the transportation graph: IN , OUT or INOUT . T de nes the type of the object, n is a variable used to reference the object, and e1 is an optional expression for variable initialization. D is a graph directive that de nes the transportation path along which the object will be transported. It is possible to reassign the value of variable n at vertices along the transportation graph. V refers to a vertex in the transportation graph, and e2 is an expression that n should be assigned to at V . Flowing IN indicates the transported object is passed into vertices during traversal. Flowing OUT indicates the variable n is carried out of vertices during traversal. Flowing INOUT indicates the transported object is passed into and out of vertices during traversal. Transportation is implemented by extending the signature of vertices along the transportation graph to include additional formal parameters. The transported objects are passed into and out of methods through the argument parameters. Code fragments specify task-speci c behavior, aside from traversal and transportation, and are represented in a textual form as: WRAPPER VE PREFIX (@ C++ statements @) SUFFIX (@ C++ statements @)
A PREFIX wrapper indicates code to be be performed before any traversal behavior for vertex or edge VE , SUFFIX wrappers indicate code to be performed after traversal behavior.
3 Testing Adaptive Software Traditional software testing is performed in several phases, namely unit testing , integration testing and system testing . Tests are either speci cation-based (black box) or program-based (white box). For procedural programs,
unit testing refers to testing a speci c procedure, while integration testing implies testing the dependencies and interactions between several procedures. System testing involves testing the complete integration. Most models of testing object-oriented programs de ne unit testing as testing an individual class and its methods (intra-class testing). In reality this entails a combination of unit testing (individual class methods) and integration testing (interactions between methods of a single class). Object-oriented integration testing is considered to be testing class collaboration and method calls between classes (inter-class testing). 13
Adaptive software is developed and tested in several phases. Unit testing refers to the testing of an individual propagation pattern (intra-propagation pattern testing), while integration testing involves testing the interactions between several propagation patterns (inter-propagation pattern testing). Integration is performed at many levels, with integrated components potentially being further integrated into many programs. Propagation patterns are initially unit and integration tested using the representative class dictionary graph. Customization may require additional integration testing, but unit testing for a customizer is minimal.
3.1 Unit Testing a Propagation Pattern The code generated [16] by customizing a propagation pattern with the representative class dictionary graph will be represented in a Uni ed class dictionary graph [4]. The uni ed class dictionary graph is used to depict control ow, control dependence, data ow and data dependence of object-oriented programs. Test case adequacy can be assessed using various coverage measures, which are developed by computing possible paths in the uni ed class dictionary graph. The uni ed class dictionary graph consists of several layers of subgraphs, each serving a particular purpose in the testing process. The rst layer contains a class dictionary graph describing class structure, built above it in the next layer is a Behavioral Class Dictionary Graph , providing a graphical representation of behavior. The vertices in the behavioral class dictionary graph represent class methods, the expressions they contain, and the variables the expressions work on. The graph depicts the control ow of expressions in a method, and call edges show inter-method dependencies. Polymorphic calls are depicted with dynamic call edges. The behavioral class dictionary graph can easily be augmented to show control dependence and data dependence. Figure 6 contains the behavioral class dictionary graph for the overDue propagation pattern. Test cases will be built to cover the dierent paths in the graph, including the dynamic call edge. The layer above a behavioral class dictionary graph is called an Intermethod Flow Graph and shows the ow of objects during method calls. This layer denotes the ow and dependence of objects through parameters, method host objects, object sub-state, and method returns. The graph is used to compute test case adequacy for data ow and dependence. Test cases exercise the paths between de nitions and uses of variables across method boundaries. An important distinction between the intermethod ow graph and traditional data ow representations is the ability to address polymorphism and dynamic binding across method boundaries, and the 14
Company::overDue
ClassName
Order::overDue
L
ClassName
Alternation Vertex
MethodID
Method Vertex
o E1
Entry
Exit
Exit
Order
Entry
D E1 orders
E6 =
D E6
FilledStatus::overDue
E7
D
S
E7 o
E7 E6 this filled
o
= ID
ID
While
UnFilled::overDue
L
Order_list Order _iterator
Entry
ID
F 1 o
each
next
ID
Order
OrderList::overDue
L
MethodID
F 1 o
A
Exit Entry
Construction Vertex
If
Virtual Method Vertex Assignment Expression Vertex Message Expression Vertex
While Conditional Expression Vertex If Conditional Expression Vertex
Expr.ID
Order
name
Exit
Term Vertex Call Edge
E2 ? While T
D
? E5
E3 = S E4
D
E5 each
Order_list_Iterator::operator()
T
E9
D
E3 each E4 next
E8 IF
D
E11
E12
D
D
D
E10 o
E11 o
Dynamic Call Edge Control Flow Edge Destination Edge Source Edge
D S
A
E9 due
E10
E12 due
A
E9
F
Acutal Parameter Edge
ord
Formal Parameter Edge
label
today()
Date::operator