MODELING AND MARSHALING: MAKING TESTS FROM MODEL CHECKER COUNTEREXAMPLES Paul E. Black National Institute of Standards and Technology Gaithersburg, Maryland paul.black@nist.gov ABSTRACT Recently model checkers have been applied to software areas such as analyzing protocols and algorithms, measuring test adequacy, and generating abstract tests from formal models. When using model checkers to generate tests, the generated tests are execution traces of the models. Thus the type, occurrence, and order of variables, calls, and events in the execution traces are intimately tied to the choice of modeling representation. We briefly review how to use a model checker to generate tests from a high-level representation, such as MATLAB?, UML, or SCR. Since the model checker uses a particular general model, the analyst has choices about how a piece of software may be modeled. We list some choices and discuss their advantages and disadvantages. We also describe a program to marshal model variables from resultant model checker traces and translate them into function calls, program variables, and other software artifacts. INTRODUCTION A model checker is a formal evaluation tool whose inputs are a state machine and a set of temporal logic predicates on possible executions of the state machine. If a predicate is not true, that is, inconsistent with the state machine, the model checker reports the inconsistency and gives a counterexample, if possible. A counterexample is an execution trace of the state machine showing how the predicate is false. Among the popular model checkers are SMV [1] and Spin [2]. Figure 1 is an example of a simple state machine specification in SMV. One variable, pressure, is an input, that is, its value may change arbitrarily. The other variable, mode, is just a discrete summary of pressure. VAR mode: {tooLow, okay, tooHigh}; pressure: 0..300; ASSIGN mode := case pressure > 150: tooHigh; pressure >= 50: okay; 1: tooLow; esac; Figure 1. A State Machine Specification in SMV In addition to the state machine, we can declare predicates quantified over possible alternative executions or over future states. For instance, we may say that in all states, the mode may be too high eventually. We may also say that in all states, if the pressure is less than 50, the mode is too low. SPEC AG EF mode = tooHigh SPEC AG (pressure < 50 -> mode = tooLow) The temporal operator AG means for all (A) alternative executions and for all states along (G) paths beginning at the current one, the predicate holds. The operator EF means there exists (E) some alternative execution in which there exists some future (F) state where the predicate holds. Briefly, the first predicate says, "For all states, mode may become too high." Although model checking began as a method for verifying hardware, it has successfully been used to analyze software, such as air traffic flight rules, protocols, operating systems, and security. Its advantage over other formal methods is that although some models may take exponential time, checking predicates is completely automatic. GENERATING TESTS FROM SPECIFICATIONS In this section we outline a relatively new method to automatically generate complete test cases from specifications [3]. The method is automatic since human input is not needed once the model is created. Before describing the method, let us define a few terms. A complete test case includes expected output, as well as input. A test criterion is the overall strategic goal, or a judgment about what aspects one wishes to test. Some criteria are code branch coverage, boundary testing, random testing, use cases, or mutation adequacy. A test objective is a specific, tactical goal. Here are some typical test objectives. * Execute the program so branch #27 is not taken. * Choose inputs just within the x= file_level; Consider the possible results if the process level is three, the file level is five, and the new level is two. Since the process level is less than the file level, the operation fails in the actual system. SMV could consistently make the status zero (fail) and the file level five (unchanged). However since SMV has parallel assignment and constraint satisfaction, it could also consistently make status equal to one (succeed) and the file level equal to two (the new level), which is wrong! Splitting the computation between steps prevents a dependency loop between variables. The preceding example may be corrected by referring to the status in the current step, not the next step. next(file_level) := case status: next(new_level); 1: file_level; esac; status := proc_level >= file_level; Figure 5 diagrams the two-phase update that prevents a dependency loop. We leave out the new level to make the diagram clearer. Note that the status is computed from the values in the same simulation step, and the file level is computed from the previous status. (Figure not available) Figure 5. Two-Phase Update Prevents Loops. The configuration file for this model reflects the skew in the variables. The process level is carried from one step to the next step where it is used with the new level and the resulting file level. The status is not reported because it is an artifact of modeling, not a value in the software. We want to report new level and check the file level every step whether they change or not, so they are marked accordingly. variableSkew = { proc_level STEP new_level, EVERY file_level, EVERY } Both the status computation and state update are delayed until the next step in the variant diagrammed in Figure 6. The change to the SMV is to refer to next(status) in both the computation of the next file level and the left hand side of the status computation. The diagram in Figure 6 makes the difference quite apparent. (Figure not available) Figure 6. Two-Phase Update, Delayed. Implementation Skew The final example we show is implementation skew. Some software is event, or edge, sensitive, instead of value, or level, sensitive. That is, we need some history to determine the next state. In SMV this history must be kept by new variables that hold previous values of variables. For instance, the automobile cruise control mode [3] changes from cruise to override when the brake is pressed. When the brake is released, the mode remains override until Resume goes true. Even if Resume were true when the brake is released, the mode would stay override: there must be a Resume event, that is, it was false and becomes true, for the mode to return to cruise. Figure 7 shows the skew of variables holding previous values. (Figure not available) Figure 7. Implementation Skew. FUTURE WORK We are recruiting industrial and academic groups to develop an open-source reader for Matlab Stateflow and Simulink models. In addition to being available for other analysis tools, we will use the reader as the basis of a tool to convert Matlab models to SMV. We are also working on a UML StateChart to SMV converter. Along with researchers at UMBC and GMU, we are working on identifying and grading additional test criteria, such as mutation adequate and transition pair coverage. We hope to be able to suggest which criteria will be best for different specification styles and testing needs. Finally we are applying these techniques to large, real specifications from industry to further validate them and make them practically useful. The marshaling program must be more flexible, intuitive, and complete. CONCLUSIONS We explained a recent technique to automatically generate complete tests from formal specifications. We have also shown how modeling decisions affect resulting counterexamples. This paper outlines a table-driven program to reverse modeling transformations so the tests correspond to the original software. Eventually all designers should benefit from having a "bag of tricks" which include state machine modeling and variable marshaling techniques. [1] McMillan, Kenneth L., 1993, Symbolic Model Checking, Kluwer Academic Publishers. [2] Holzmann, Gerald J., 1997, The Model Checker SPIN, IEEE Trans. on Software Eng., 23(5), pp. 279-295. [3] Ammann, Paul A., Paul E. Black, William Majurski, 1998, Using Model Checking to Generate Test from Specifications, Proc. 2nd IEEE Intern'l Conf. on Formal Eng. Methods, IEEE, pp. 46-54. [4] Atlee, Joanne M., M. A. Buckley, 1996, A Logic-Model Semantics for SCR Software Requirements, Proc. 1996 Intern'l Symp. on Software Testing and Analysis, pp. 280-292. [5] Ammann, Paul A., Paul E. Black, 1999, Abstracting Formal Specifications to Generate Software Tests via Model Checking, Proc. 18th Digital Avionics Systems Conf., IEEE, section 10.A.6. [6] Majurski, William J., 2000, Issues in Software Component Testing, to appear in Computing Surveys, ACM.