rs@uunet.UU.NET (Rich Salz) (09/10/87)
Submitted-by: "Mark A. Ardis" <maa@sei.cmu.edu> Posting-number: Volume 11, Issue 38 Archive-name: test.el/Part03 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # MANIFEST # test.texinfo export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'MANIFEST'" '(1149 characters)' if test -f 'MANIFEST' then echo shar: "will not over-write existing file 'MANIFEST'" else sed 's/^X//' << \SHAR_EOF > 'MANIFEST' XFile Archive Description X---- ------- ----------- XMANIFEST 1 This file Xbox.script 2 Example test script Xexample.texinfo 2 Appendix part of user manual Xhooks.el 2 Example hooks for customization Xtest.el 2 Root of test package Xtest.texinfo 1 Main part of user manual Xtst-achieve.el 2 Achieve-state routines Xtst-analyze.el 2 Analyze test results Xtst-annotate.el 2 Annotate package with results Xtst-capture.el 2 Capture-state routines Xtst-display.el 3 Display test results Xtst-equal.el 3 Test states for equality Xtst-inequal.el 3 Modifications to notion of equality Xtst-instrument.el 3 Instrument package for testing Xtst-utilities.el 2 Miscellaneous utilities Xuser.texinfo.el 2 Wrapper for hard-copy user manual SHAR_EOF if test 1149 -ne "`wc -c < 'MANIFEST'`" then echo shar: "error transmitting 'MANIFEST'" '(should have been 1149 characters)' fi fi echo shar: "extracting 'test.texinfo'" '(60887 characters)' if test -f 'test.texinfo' then echo shar: "will not over-write existing file 'test.texinfo'" else sed 's/^X//' << \SHAR_EOF > 'test.texinfo' X@setfilename test X@node top, introduction, , (dir) X@ifinfo XThere should be more nodes than listed below, but at least the chapters are Xisolated. X@menu X* introduction:: Purpose of the package. X* starting:: How to get started. X* testing:: Testing a package. X* instrumenting:: Instrumenting to measure testing effectiveness. X* analyzing:: Analyzing the results of testing. X* displaying:: Displaying the results of analysis. X* running:: Running a testscript in batch. X* epilogue:: Final words. X* example:: An example package to test. X@end menu X@end ifinfo X@node introduction, starting, , top X X@chapter Introduction X XThis document explains how to use the Test package to test GNU Emacs Xpackages. It is an extension of Chapter 22 [Compiling and Testing XPrograms] of the GNU Emacs Reference Manual. X X@section Purpose of the Package X XThis package provides tools to aid in developing regression tests for Emacs Xpackages and to assess the efficacy of those tests. GNU Emacs packages, Xwritten in a dialect of Lisp, provide extensions to the basic text editing Xfeatures of Emacs. Most of these packages perform state-changing Xoperations. For example, a package may create new buffers, modify text, Xchange the locations of the cursor and various marks, write files or modify Xanything else accessible to Emacs (which is just about everything in Unix). XTraditional Lisp debugging strategies are not sufficient to adequately test Xa package that performs extensive state-manipulation. The Test package Xprovides a strategy that is. X X@section Test Approach X XThe Test system is designed to support structural (or ``white-box'') Xtesting. (Another commonly used test approach is functional, or X``black-box'' testing.) It automates the process of running a number of Xtests cases designed to analyze ``coverage'' of the package (that is, find Xparts of the code that are not exercised) and ``expression'' (that is, what Xvalues are returned by each expression, and which expressions always Xreturned the same values). X X@section Testing Method X XTest provides mechanisms to ease the creation and execution of sets of Xtests. Some of the features are designed to simplify testing activity, Xwhile others are designed to aid the analysis of testing. X XTest supports coverage testing. That is, it provides instrumentation Xmechanisms designed to check for inadequacies of testing of the following Xtwo forms: X@itemize @bullet X@item XFailure to execute an expression. X@item XFailure to produce more than one value for an expression. X@end itemize XIn each case, the fault may be in the tests (i.e., not enough testing was Xperformed), or the fault may be in the program (i.e., an ``unnecessarily Xcomplex'' program has been written). (There is also the possibility that Xno fault exists, such as the use of ``constant'' functions for readability Xor style. In practice these cases are easy to identify and ignore.) X XYou should use the following strategy in creating tests with this Xsystem: X@enumerate X@item XCreate a simple set of tests that appear to be necessary to test the basic Xfunctionality of the package. X@item XAdd additional tests to ensure that every expression is executed, and that Xeach expression produces at least two values over the entire set of tests. X@item XRun the set of tests with instrumentation to check for inadequacies. X@item XIf there are reported inadequacies, then correct the code or improve the Xtesting, and go back to the previous step. X@end enumerate XThere is no guarantee that a set of tests that passes these coverage checks Xwill find all errors. But, such a set of tests has the property that every Xexpression in the code has been exercised in a minimally significant way X(i.e., every expression has produced at least two different values). In Xpractice, a great number of errors can be detected with this method. X XThe importance of coverage testing increases as a package is modified. XChanges to one part of a package may have unexpected effects on other X(unconsidered) parts. Coverage testing ensures that all parts of a package Xare tested, at least minimally. Coverage tests also serve as a Xspecification of the functionality of a package. X XFigure 1 illustrates the overall flow of events using this test Xapproach. X X@group X@example X +------------+ +--------------+ X | Instrument | | Generate | X | o Control | | o Test Cases | X | o Data | | o Script(s) | X +------------+ +--------------+ X \ / ^ X \ / | X \ / | X \ / | X \ / | X \ / | X +-------------+ | X | Execute | | X | the | | X | Test(s) | | X +-------------+ | X | | X | | X +-------------+ | X | Analyze, | | X | Display | | X | Results | | X +-------------+ | X | | X | | X ^ | X / \ | X / \ No | X < Done? >-------------+ X \ / X \ / X \ / X v X | Yes X |(Test Goals Achieved) X V X X X X@end example X@center Figure 1. General Test Algorithm X@end group X X@section Overview X XThe Test product consists of four major subsystems: X@itemize @bullet X@item XRegression Subsystem -- a set of functions to support regression testing of XEmacs packages. X@item XCoverage Subsystem -- a set of functions to support coverage testing of XEmacs packages. X@item XAnnotation Subsystem -- a set of functions to provide support for creating, Xusing and displaying information about Emacs Lisp code. X@item XEquality Subsystem -- a set of functions used by the testing Xsubsystems that provide different interpretations of equality. X@end itemize X XThe following sections explain the use of these functions to support Xthe steps in the testing process: X@itemize @bullet X@item XGetting Started X@item XInstrumenting a package X@item XTesting a Package X@item XAnalyzing Test Results X@item XDisplaying Test Results X@end itemize X XThe system is designed to test Emacs-Lisp programs, and is implemented as a Xminor mode of Emacs-Lisp mode (See Section 28.1 [Minor Modes] of the GNU XEmacs Reference Manual). X X@node starting, testing, introduction, top X@chapter Getting Started X XThis section describes how to begin using the Test package to test XEmacs packages. X X@section Loading and Initialization X XTo start testing you probably want a fresh Emacs session with no extraneous Xbuffers or processes hanging around. Non-essential extras will just slow Xdown the state capture and achieve functions. If you have a busy X@file{.emacs} file you may want to keep a trimmed back copy just for test Xsessions. X XOnce in Emacs visit the file containing Emacs-lisp code to be tested, Xthen enter: X@example XM-x load-file Xtest.el XM-x test-mode X@end example XThe mode line at the bottom of your window should show ``(Emacs-lisp XTest)'' in the mode field. You are now in Test mode. X XProbably the first thing to do at this point is to use @samp{C-c n} to Xgenerate a new buffer containing a test script template. This is a good Xstarting point for creating a new test script; the template is shown in Xsection 2.3 of this document. The task now confronting you is to develop a Xtest suite that will exercise your package throughly, not only to test it Xnow but also to have an automated regression test. The remainder of this Xdocument will guide you through this task. X XFigure 2 illustrates the overall flow of data in the Test system. X X@group X@example X +-------------+ X |Source Text | X +-------------+ X \ X \ X \ X Instrument X / X / X / X +-------------+ +-------------+ X |Instrumented | | Test Cases | X | Text | +-------------+ X +-------------+ / X \ / X \ / X \ / X \ / X Execute X \ X \ X \ X \ X +-------------+ X |Test Results | X +-------------+ X / ^ X / | X / | X / v X Display Analyze X X X X@end example X@center Figure 2. Test Data Flow X@end group X X@section Test Mode X XThe package `@samp{test.el}' provides several functions to the user: X@table @samp X@item C-c n XStart a new test script X@code{ (tst-new-script-buffer)} X@item C-c i X(Re-)instrument a test program buffer @code{ (tst-instrument)}. X@item C-c x XTest the program, using the test script @code{ (tst-execute)}. X@item C-c c XRecord a GNU Emacs state for later use X@code{ (tst-capture-state)}. X@item C-c a XAchieve a previously saved GNU Emacs state X@code{ (tst-achieve-state)}. X@item C-c C-a XAchieve a state previously saved-to-file X@code{ (tst-achieve-state-from-file)}. X@item C-c C-c XCapture current emacs state to file X@code{ (tst-capture-state-to-file)}. X@item C-c C-r XRead a previously saved-to-file state into a variable X@code{ (tst-read-state-from-file)}. X@item C-c C-w XWrite a state previously captured in a variable to a file X@code{ (tst-write-state-to-file)}. X@item C-c f XAnalyze (filter) the results of running the test(s) @code{ (tst-analyze)}. X@item C-c d XDisplay the annotations about the test @code{ (tst-display-mode)}. X@item C-c q XExit test mode @code{ (test-mode)}. X@end table X X@section Contents of the *test script* Buffer X X X@example X(defun test-script () X (interactive) X ; Local Variables X (let (pre post actual) X ; Body X (switch-to-buffer foo) X (erase-buffer) X (insert-file foo) X (goto-char (point-min)) X (emacs-lisp-mode) X (test-mode) X (tst-instrument) X ; 1st test run X (tst-read-state-from-file 'post expected-state-file1) X (tst-achieve-state-from-file 'pre initial-state-file1) X (foo args) X (tst-capture-state 'actual nil nil) X;;; If you have a lot of tests, consider a while loop X ) ; let X) ; defun X@end example X X@section The Example -- box.el X XThe package `@samp{box.el}' provides two functions to the user: X@code{box-region} and @code{unbox}. XThe first function encloses the current region with a box: X X@group X@example X/********************************************\ X* A boxed region * X* may have lines of text of varying lengths. * X* A side effect of boxing is to normalize * X* the length of lines. * X\********************************************/ X@end example X@end group X XThe second function undoes the effect of the first by removing any boxes Xwithin the region. This simple package will be used in this document as an Xexample of a package to be tested using the Test package. X X@node testing, instrumenting, starting, top X@chapter Testing Your Package X XAs mentioned at the beginning of this document, Emacs packages are Xgenerally state changing operations. You invoke the package with a session Xthat is in some arbitrary @i{initial state}. The package modifies Xselected aspects of this @i{initial state} in a defined manner and leaves Xthe session in some @i{final state}. The @dfn{state} of a GNU Emacs Xsession consists of information on buffers, windows, processes, and other Xglobal information. The components of the state that are used in the Test Xpackage are listed later in this section. X X@dfn{Regression Testing} is a technique for verifying that changes in a Xpackage do not unintentionally degrade the quality of the code. Any Xchanges in one part of the package should not alter the functionality of Xother parts of the package. State information plays two roles in Xregression testing of Emacs packages. These are: X@enumerate X@item Xinitiating the run of a package in a consistent and Xpre-determined @dfn{initial state}, and X@item Xcomparing the @dfn{actual final state} after the completion of a Xpackage to a @dfn{desired final state}. X@end enumerate XThe regression testing components of @samp{test.el} allow you to X@dfn{capture} session states for later use, @dfn{achieve} these states to Xset up a test run, and test the @dfn{equality} of states for package Xverification. X XThe following example demonstrates these steps for regressions testing an Xarbitrary package. Assume that a working version of some package exists. XNow suppose you wish to add some new function that requires some Xmodifications in the original code. After adding the new function you need Xto verify that the original functionality of the package has not changed. XIn other words, you need to verify that the code has not @dfn{regressed} Xfrom its original functionality. To perform this testing, you X@dfn{capture} the initial state of a session, run the original package, and X@dfn{capture} the final state. Following this, you @dfn{achieve} the Xinitial state that you previously captured, run the new version of the Xpackage, and perform an @dfn{equality} test to compare the new final state Xto the one that was captured after the run of the original package. The Xstates should be equivalent if the test is successful. X XTwo extensions to this state comparison paradigm are: X@enumerate X@item XTesting for partial equivalence - Each Emacs package is supposed to change Xcertain aspects of a session state, but leave others unchanged. For Xexample, a package may change the text of the current buffer but should Xleave the window configuration of the session intact. Partial equivalence Xtesting consists of the following steps: X@enumerate X@item XCapture the initial state. X@item XRun the function to be tested. X@item XCompare the final state to the initial state. The states should be Xequivalent in all areas except those that the test function is supposed to Xchange. X@end enumerate X@item XTesting functions that undo the effects of other functions - Some emacs Xpackages have a function that perform some state change and a corresponding Xfunction that undoes that change. Testing these types of packages consists Xof the following steps: X@enumerate X@item XCapture the initial state. X@item XRun the function that performs the state change. X@item XRun the function that undoes the state change. X@item XCompare the final state to the initial state. They should be equivalent. X@end enumerate X@end enumerate XThe remainder of this section describes the elements of the Test Xpackage that implement these aspects of regression testing. XIn summary, these are: X@itemize @bullet X@item X@code{capture} - saves the current state of the Emacs session Xin either a bound variable or UNIX file. X@item X@code{partial capture} - save part of the current state of the XEmacs session. Some or all global variables may be excluded, and a subset Xof buffers may be selected. X@item X@code{achieve} - sets the state of the current session to one Xthat is either in a bound variable or a UNIX file. X@item X@code{equality} - compares two emacs sessions states for Xequivalence. X@item X@code{partial equality} - compares selected aspects of two emacs Xsession states for equivalence. X@item X@code{inequality} - using user defined hooks, compares two Xsession states within certain degrees of inequality (e.g. compares buffer Xcontents ignoring whitespace). X@end itemize X X@section Capturing and Achieving Emacs States X X@subsection GNU Emacs State Definition X XThe @dfn{capture} and @dfn{achieve} functions of @samp{test.el} represent Xan Emacs state as the hierarchy of data shown below. X@itemize @bullet X@item X@code{Global Bound Symbols} - Most of the information about an XEmacs session is contained in the values of symbols global to the session. XIn conventional programming language terms, this session information can be Xviewed as the values of global variables. Some examples of common global Xbound symbols are: X@itemize @bullet X@item X@samp{global-abbrev-table} - the list of abbreviations global to Xthe session and their meanings. X@item X@samp{global-map} - a vector describing the mappings of all keys Xto Emacs commands. X@item X@samp{debug-on-error} - a flag that indicates that the Emacs Xdebugger should be called on an error (if non-nil). X@end itemize X@item X@code{Buffer Information} - Each Emacs session contains one or Xmore buffers. The capture functions store the following information for Xeach active buffer: X@itemize @bullet X@item Xbuffer name - a unique name that identifies the buffer. X@item Xfile name - if the buffer is associated with a UNIX file, the Xname of that file. X@item Xpoint - the value of the cursor point in the buffer. X@item Xmark - the value of the buffer's mark. X@item Xcontents - the contents of the buffer represented as a text string. X@item Xmodified - a flag indicating if the buffer has been modified Xsince last saved. X@item Xlocal map - the local key map for this buffer. X@item Xlocal bound symbols - symbols (variables) that are local to this Xbuffer (e.g., the @samp{current-mode} of the buffer). X@end itemize X@item X@code{Window Information} - At any time an Emacs session has Xone or more windows visible. The capture functions store the following Xinformation for each window: X@itemize @bullet X@item Xedges - the upper left and lower right corner of the window in Xscreen coordinates. X@item Xbuffer - the buffer occupying this window. X@item Xstart - the integer position in the buffer where display starts Xin the respective window. X@item Xpoint - the integer position in the buffer where the point for Xthis window sits. X@item Xcurrent flag - a flag that is non-nil if this is the window in Xwhich the screen cursor currently is located. X@end itemize X@item X@code{Process Information} - An Emacs session may have invoked Xseveral UNIX processes during its lifetime. These processes may have Xcompleted or may still be running. Two common processes that run during an XEmacs sessions are the @samp{shell} and the process that displays the time, Xdate and system load on the @dfn{mode line}. The @samp{Test} capture Xfunctions store the follow information for each process: X@itemize @bullet X@item Xbuffer - the name of the buffer to which the process is attached X(nil if the process is not related to a buffer, e.g., the display time Xprocess). X@item Xprocess mark - the marker for the end of the last output from Xthe process. X@item Xcommand - the UNIX command that invoked the process. X@item Xexit status - if the process has completed, the UNIX return code Xfrom that process. X@item Xfilter - the name of an Emacs lisp function that receives all Xoutput of the process. X@item Xname - a unique name of the program invoked in the process. X@item Xsentinel - the name of an Emacs lisp function that is called Xwhen the process changes state (e.g. completes). X@item Xstatus - indicates whether the process is running, complete, Xetc. X@end itemize X@end itemize X XA significant item that is excluded from this state information is the Xcurrent definition of bound functions. Recall that an Emacs user can Xdefine any new function with a @samp{defun} and load that function. XFurthermore, the user can redefine any existing function (e.g. X@code{forward-char} !) in this manner. Saving the current definition of Xall bound functions would result in a huge state vector, and is therefore Xnot done. X X@subsection Capturing an Emacs Session State XWhen regression testing an Emacs package, you will mainly use the state Xcapture functions of Test in two ways: X@enumerate X@item Xto save a known @dfn{initial state} to use as the base state for Xa run of an Emacs package, and X@item Xto save a @dfn{final state} to later compare to the state of the Xsession after the run of a modified package. X@end enumerate X X@subsubsection Commands for Capturing State X X@table @samp X@item tst-capture-state-to-file XWrites the current state of the Emacs session to a file. You are prompted Xfor the name of the file, the @dfn{exclude-variables} and the X@dfn{buffer-list}. Refer to the @code{Usage Notes} below for details on Xthese last two items. If the file you specify already exists it is Xoverwritten. X@item tst-write-state-to-file XWrites a state that is saved in a bound variable to a file. You are Xprompted for the state variable name (which was created with X@samp{tst-capture-state}) and the name of the file. If the file already Xexists it is overwritten. X@item tst-capture-state XSaves the state of the Emacs session in a state variable. You are prompted Xfor the name of the file, the @dfn{exclude-variables} and the X@dfn{buffer-list}. Refer to the @code{Usage Notes} below for more details Xon these last two items. If the bound variable you specify already exists, Xit is overwritten. X@end table X X@subsubsection Usage Notes X XThe amount of information saved by @samp{tst-capture-state-to-file} and X@samp{tst-capture-state} is controlled by your responses to the command Xprompts. These are: X@table @samp X@item List of buffers to capture: XThere are three possible responses to this prompt: X@enumerate X@item X@samp{nil} to indicate that state information on all buffers should be Xsaved (the default). X@item XA list of of buffer names indicating for which buffers state information Xshould be saved. For example, to save only the states of buffers X@samp{bar} and @samp{foo} you enter: X@example X ("bar" "foo") X@end example X@item XA singleton list that is the name of a non-existent buffer if you do not Xwish to save any buffer state information. For example, if no buffer X@samp{xxx} exists you could enter X@example X ("xxx") X@end example Xto specify that capture not save any buffer state information. X@end enumerate X@item List global vars to exclude: XThere are three possible responses to this prompt: X@enumerate X@item X@samp{nil} to capture all global variables. X@item X@samp{all} to exclude all global variables from the captured Xstate. X@item XA list of global variable names to exclude from the captured state. For Xexample, if you enter X@example X ("obarray" "values") X@end example Xthe two global variables, @samp{obarray} and @samp{values}, are not Xcaptured. This value is the default for the prompt since these two Xvariables have very large values that are rarely of use in testing. X@end enumerate X@end table X X@subsection Achieving an Emacs State X XWhen using Test you will mainly use the achieve state functions to return Xyour session to a known @dfn{initial state}. With these functions you can Xmake repeated test runs by simply achieving the @dfn{initial state} between Xeach run. X X@subsubsection Commands for State Achieve X@table @samp X@item tst-read-state-from-file XReads a session state from a file into a bound symbol. You are prompted Xfor the name of the file and the name of the bound symbol. The file should Xhave been created by @samp{capture-state-to-file} or X@samp{write-state-to-file}. If the bound symbol already exists, it will be Xoverwritten. X@item tst-achieve-state-from-file XSets the state of the emacs session to that saved in a file. You are Xprompted for the name of the file. The file should have been created by X@samp{capture-state-to-file} or @samp{write-state-to-file}. X@item tst-achieve-state XSets the state of the emacs session to that saved in a bound symbol. You Xare prompted for the name of the bound symbol. The symbol must have been Xcreated by @samp{tst-capture-state}. X@end table X X@subsubsection Usage Notes X XAchieving the state of a previous Emacs session is a non-trivial task that Xcan have many unexpected side-effects. These are listed below: X@enumerate X@item XIf you want @samp{achieve} to preserve all existing buffers that were not Xpart of the state you are achieving, you may set the variable X@samp{tst-achieve-buffers-nondestructively} non nil. X@item XAchieving a previous state completely resets your Emacs session. Any Xinformation in your current state will be overwritten by the achieved Xstate. For example, any changes in buffers will not exist after the Xachieve process. You should, therefore, make sure that you save any Xchanges to disk before running achieve. X@item XIf you are not careful you may find that previous versions of disk files Xoverwrite current changed versions. The following scenario demonstrates Xthis problem. X@enumerate X@item XSuppose you have a file @samp{mytest} that is in a buffer of an emacs Xsession at the time you run @code{tst-capture-state-to-file}. X@item XNow suppose you make changes to this file over a period of a few days, and Xthen run @code{tst-achieve-state-from-file}. X@item XYour emacs session will now contain the old version of the file. X@item XIf written to disk, this old version will overwrite the current version of X@samp{mytest}. X@end enumerate X XYou can avoid this problem by testing packages only on dummy test files, or Xusing a special test directory with copies of files that are permanently Xstored in other directories, or by not capturing buffer @samp{mytest} and Xsetting @code{tst-achieve-buffers-nondestructively} to @code{t}. X X@item XThe state of an emacs session is partially dependent on the state of your Xentire UNIX session. Therefore, the achieve state functions may not be Xable to restore your state to the exact one that was captured. For Xexample, a process can not be started if the run image for the program no Xlonger exists on disk. When testing and comparing states, it is best to Xrely only on the more common aspects of an Emacs session (e.g. buffers, Xwindows). X@item XAs explained earlier, the capture functions do not save all aspects of the Xsession. A significant example is the current definition of all bound Xfunctions. Therefore, the achieve functions will not restore these aspects Xof the session state. X@end enumerate X X@section Testing for equality X XThe equality package of @b{Test} compares two Emacs states for equivalence Xby invoking special equality functions on each of the data components Xcaptured in the state. Each of these equality functions compares only a Xsmall part of the entire state. The results of these comparisons are Xwritten into the buffer @samp{*equal-log*}. If two states are not equal Xthen you can determine where components differ by looking at this buffer. X XThe section @b{Equality Functions} provides a list of all of the Xequivalence testing functions. The section @b{Partial Equality} explains Xhow you can accomplish testing a subset of a state. This is useful if you Xare only interested in differences between certain aspects of state, such Xas only the contents of buffers, but you do not care to hear about Xdifferences in other components, such as windows. The section X@b{Inequality} explains how to add hooks to the equality functions. These Xhooks are called by the equality functions when two components are not Xequal but before a result is returned. A hook that you write can be Xinserted at this point and change a ``not equal'' result into an ``equal.'' X X@subsection Equality Functions X XThe functions to compare states for equality are divided into two Xcategories. One set of functions compares complete states, the second set Xof functions only uses the buffer components. X XThe following state equality functions are defined for interactive use. X@table @code X@item tst-equ-state XCompares two states for equality. Each component in the first state is Xcompared to its corresponding component in the second state. X@item tst-equ-sessions XCompares the @b{sessions} component of two states. The sessions components Xcontains all global variables. These includes those that define key-maps Xand syntax tables. X@item tst-equ-buffers XCompares the @b{buffers} components of two states. Compares all of the Xbuffers in one state with those of a second state. X@item tst-equ-windows XCompares the @b{windows} components of two states. X@item tst-equ-process XCompares the @b{process} components of two states. X@end table X XThe following functions operate on just the @b{buffer} components of Xstates. Objects of this type can be extracted from state objects by the Xfunction @code{tst-equ-find-buff-with-name}. X@table @code X@item tst-equ-buffer-state XCompares two buffers for equality. The following components are checked for Xequality: @b{point}, @b{mark}, @b{contents}, @b{modified}, @b{file}, X@b{local-variables}. X@item tst-equ-point XCompares the @b{point} component of two buffers. X@item tst-equ-mark XCompares the @b{mark} component of two buffers. X@item tst-equ-file XCompares the @b{file} component of two buffers. X@item tst-equ-modified XCompares the @b{modified} component of two buffers. X@item tst-equ-contents XCompares the @b{contents} component of two buffers. Contents are compared Xas two single strings. X@item tst-equ-contents-line XCompares the @b{contents} component of two buffers. Contents are viewed as Xcomposed of lines of text, and compared line-by-line. X@item tst-equ-contents-region XCompares the @b{contents} component of two buffers. Only the contents Xwithin a region are compared. Region is delimited by point and mark. X@end table X X@subsection Partial Equality X XIf you are interested in only checking the equality of a subset of an Emacs Xstate, then there are four methods you can use. X X@table @code X@item tst-capture-state XYou can use this function to capture only a subset of state. Once this has Xbeen done, equality testing will only be performed on those parts of the Xstate that where captured. X@item tst-equ-state-functions XThis variable contains a list of equality functions to be invoked when Xcomparing two states. You can change it to test only those components of Xstate that interest you. As an example, you might want to remove X@samp{tst-equ-windows} if you are not interested in differences in windows Xbetween states. X@item tst-equ-buff-state-functions XThis variable contains a list of equality functions to be invoked when Xcomparing two @dfn{buffer states}. You can change it to test only those Xcomponents of @dfn{buffer state} that interest you. As an example, you Xmight want to remove @samp{tst-equ-point} and @samp{tst-equ-mark} if you Xare not interested in those parts of the states. X@item tst-equ-find-buffer-with-name XUse this function to obtain only the part of state that is associated with Xa particular buffer. You can then pass the result of this function to Xbuffer testing equality functions. X@end table X X@subsection Inequality X XSometimes the comparison of two objects yields ``not equal'' when wish to Xignore certain inequalities. Each of the equality functions will execute a Xhook, if one is defined, and the comparison of the two objects yields ``not Xequal.'' Within the hook you can write your own test for equality and Xchange the result of the comparison if you so desire. X XFor each equality function, there exists a hook symbol that, when defined, Xwill be run if the two objects are not equal. The name of the hook symbol Xcan be found by adding @samp{-hook} to the equality function name. The Xvalue of this hook should then be set to the name of the hook function you Xwish to execute. From within the the hook the two objects being compared Xcan be accessed by adding @samp{1} and @samp{2} to the equality function Xname. The variable @code{tst-equ-result} should be set to @samp{t} or X@samp{nil} from within your hook. X XThe following example shows a hook, called @code{ignore-zero-points}, that Xis executed whenever the result of comparing the point components of two Xbuffers is not equal. From within this function the two point components Xare accessed as @samp{tst-equ-point1} and @samp{tst-equ-point2}. The hook Xchanges the result of a point comparison from @samp{nil} to @samp{t} if one Xof the points is at position zero. X X@example X X(setq tst-equ-point-hook 'ignore-zero-points) X X(defun ignore-zero-points () X "Equality point hook, changes result to t if one point X is at position zero." X X (if (or (equal tst-equ-point1 0) (equal tst-equ-point2 0)) X (setq tst-equ-result t) ; return t if one is zero X ;else X (setq tst-equ-result nil); otherwise return nil X ) X) X X@end example X XOf particular usefulness are the hooks that are associated with the Xcontents of two buffers. The equality function @samp{tst-equ-bs-contents} Xcompares the contents of two buffers by comparing strings that contain the Xentire contents of each buffer. Should this comparison fail it is sometimes Xuseful to compare the two strings after eliminating all white-space from Xeach string. The following hook, provided with this package, does such a Xcomparison. X X@example X X(setq tst-equ-contents-hook 'ignore-white-space) X Xdefun ignore-white-space() X " Compares the contents of two buffers after removing all X white-space from each." X X (setq tst-equ-result (string-equal-less-regexp "\\s " X tst-equ-contents1 tst-equ-contents2)) X) X@end example X XA second contents hook of interest is the one associated with the X@samp{tst-equ-contents-line function}. This function compares the contents Xof two functions on a line-by-line basis. The hook for this function Xdiffers from all other hooks, in that it is called once per line, instead Xof once per call to its associated function. The two lines are accessed as X@samp{tst-equ-line1} and @samp{tst-equ-line2}. X X X@section Testing example X XThe example that follows illustrates how to write an emacs-lisp function Xthat uses the Test package to test another function you have written. In Xthe example the two user supplied functions under test are: X@samp{box-region} and @samp{unbox}. X X@example X;;; test-box uses the Test package to test the functions box and unbox X;;; X test-box () X (interactive) X ; Local Variables X (let (initial-state ; to hold states X boxed-state X final-state X capture-buffer-list X ) X X ; First create a buffer to use the functions on X (get-buffer-create "box.junk") X (set-buffer "box.junk") X (erase-buffer) X (insert-file "/project/gnutest/test/box.junk") X X ; Save the initial state X ; Since we're only concerned with one buffer include X ; include that in the capture list X (setq capture-buffer-list '("box.junk")) X (tst-capture-state 'initial-state capture-buffer-list nil) X X ; execute the box function X (goto-char (point-min)) X (set-mark (point-max)) X (box-region nil) X X ; capture the boxed state X (tst-capture-state 'boxed-state capture-buffer-list nil) X X ; unbox and capture again X (unbox nil) X (tst-capture-state 'final-state capture-buffer-list nil) X X ; compare the initial state to the final state X ; they should be exactly equal X (if (tst-equ-state initial-state final-state X "Compare before box to after unbox") X (message "Box/unbox test passed") X (message "Box/unbox test failed")) X X ) ; let X ) ; defun X@end example X X@subsection Contents of *equal-log* X XEach of the equality functions writes the results of its comparison into a Xbuffer named ``*equal-log*''. If this buffer does not exist, then it is Xcreated. The contents of the buffer are never erased nor is the buffer Xever deleted, these actions are left to the user. X XThe buffer is created in Outline Mode. This allows selective hiding of Xcomparisons that are not of interest to the user. X XIf the result of a comparison is nil (i.e. not equal) then that entry in Xthe log is flagged with a question mark (?). In most cases, the two Xdiffering objects are also logged as in the following example. X X@example X* ?State comparison: Compare before box to after unbox X X** ?Sessions state X*** ? Global symbols X data-bytes-free 5350948 5176868 X this-command nil kill-region X data-bytes-used 383452 557532 X ?post not found in second state X post nil nil X ?file not found in second state X file X statevar state post X X X** ?Buffers state X X** Comparison of buffers named: *scratch* X*** point: "1" "1" X*** mark: nil nil X*** contents: contents equal X*** modified: nil nil X*** file: nil nil X*** local-vars: local variables are equal X X** Comparison of buffers named: *Minibuf-0* X*** point: "1" "1" X*** mark: nil nil X*** contents: contents equal X*** modified: nil nil X*** file: nil nil X*** local-vars: local variables are equal X X** Comparison of buffers named: box.el X*** point: "1" "1" X*** mark: 4480 4480 X*** contents: contents equal X*** modified: t t X*** file: nil nil X*** local-vars: local variables are equal X X** Comparison of buffers named: box.el-instrumented X*** point: "5608" "5608" X*** mark: 5608 5608 X*** contents: contents equal X*** modified: t t X*** file: nil nil X*** local-vars: local variables are equal X X** ?Comparison of buffers named: box.junk X*** ?point: "1" "234" X*** ?mark: 235 1 X*** ?contents: contents not equal X*** modified: t t X*** file: nil nil X*** local-vars: local variables are equal X X X** Processes state X X X** Window state X X*** window X**** window-edges: (0 0 10 9) (0 0 10 9) X**** window-buffer: "box.junk" "box.junk" X**** window-start: 1 1 X**** window-point: 1 1 X**** current-window: t t X X X@end example X X@node instrumenting, analyzing, testing, top X@chapter Instrumenting a Package X XUse the @code{tst-instrument} command for instrumenting Lisp code. XInstrumenting copies the contents of the current buffer to a new buffer Xnamed for the current buffer concatenated with @samp{-instrumented}. The Xnew buffer is set to emacs-lisp-mode. Instrumenting initializes the Xannotation data base, adds the instrumentation to the copied code, and Xfinally evaluates the entire copied buffer. X X@section Instrumentation Probes X XInstrumentation acts on certain lists that represent functions within a X@code{defun} by adding an instrumentation probe. Candidate lists are Xidentified and Lisp code is added around the list. A list representing a Xfunction that has the form, @samp{(function arg1 arg2)}, after insertion of Xthe instrumentation probe will have the form, @samp{(tst-cover #id X(function arg1 arg2))}. Instrumentation assigns the line number of the Xfunction within the buffer as the #id. X X@section Cover Function X XThe instrumentation probe consists of the invocation of the function X@code{tst-cover} with two arguments, a unique identifier and the function Xthat was instrumented. @code{Tst-cover} uses the identifier as a key into Xthe annotation data base, stores the result of the instrumented function, Xincrements an invocation counter, and returns the result of the Xinstrumented function as its function value. X X X@section Instrumentation Example X XOriginal Code: X X@example X(defun factorial (n) X (let X (result) X (if X (< n 2) X (setq result 1) X (setq result X (* n X (factorial X (1- n))))) X result)) X@end example X XInstrumented Code: X X@example X(defun factorial (n) X (tst-cover 2 (let X (result) X (tst-cover 4 (if X (tst-cover 5 (< n 2)) X (tst-cover 6 (setq result 1)) X (tst-cover 7 (setq result X (tst-cover 8 (* n X (tst-cover 9 (factorial X (tst-cover 10 (1- n)))))))))) X result))) X@end example X X@node analyzing, displaying, instrumenting, top X@chapter Analyzing the Test Results X XThis section explains how to use the @code{analyze} function X X@section Analysis Functions X XThe Coverage Analysis package is designed to run after a series of tests Xhas been performed using the instrumented version of the code under test. XIt retrieves data from the annotation database and detects the following Xtesting anomalies: X X@itemize @bullet X@item XFailure to execute an expression. X@item XFailure to produce more than one value for an expression. X@end itemize XWhen these conditions are detected additional attributes are stored in the Xannotation database in a format suitable for extraction by the display Xcomponent of Test. X XAnalysis is invoked by the command: X X@example X tst-analyze X@end example X XIf an expression is not executed, the attribute ``zero'' is inserted with a Xconstant value. This constant value is defined by the following variable: X@example X tst-anl-zero-counts X@end example X XIf an expression returns a constant value, the attribute ``constant'' is Xinserted with the value of the constant. If an expression is only executed Xonce, it is deemed to return a constant result. X XYou can re-run the analysis function without re-instrumenting the code Xunder test. If, for example, an initial set of tests indicates a number of Xunexecuted expressions, you can run additional tests and analyze the Xcombined results without re-running the complete set of tests. Note Xhowever, that if you re-instrument the code, the annotation database is Xreinitialized and the results of previous tests, including any analysis Xresults will be lost (unless you explicitly save the annotation database Xusing tst-ann-get-db). X X@section Sample Analysis Results X XNormally you would view the results of an analysis using the display Xpackage on-line. However, the following indicates the information produced Xby the analysis. X X@example X# Test analysis of box.el X# (lines which were never evaluated during tests, indicated by X# the string ``NEVER->>'', or which returned the same value X# every time they were evaluated, including the value.) X Xbox.el:31== nil Xbox.el:33== nil Xbox.el:34== nil Xbox.el:35== nil Xbox.el:37== 1 Xbox.el:38== 0 Xbox.el:39== nil Xbox.el:41== nil Xbox.el:42== nil Xbox.el:49== 1 Xbox.el:50== nil X X... X Xbox.el:94== nil Xbox.el:95== nil Xbox.el:109== #<marker at 1 in box.junk> Xbox.el:115== nil Xbox.el:116== t Xbox.el:121== NEVER->> Xbox.el:122== NEVER->> Xbox.el:128== nil Xbox.el:129== nil Xbox.el:134== NEVER->> Xbox.el:135== NEVER->> Xbox.el:140== nil X X... X X@end example X X@node displaying, running, analyzing, top X@chapter Displaying Test Results X XThe @dfn{coverage} component of the Test package is useful for measuring Xhow thoroughly a test script exercises an emacs-lisp package. The Xinteractive Test display mode lets you browse the annotated code. The Xbatch display function creates a summary report which may be browsed later Xusing the Emacs ``compilation'' mode. X X@section Display Mode---creating annotation windows X XEvaluating an instrumented buffer of emacs-lisp code creates a database of X@dfn{annotations} for each instrumented line. The two data stored during Xevaluation are: @samp{count}, the number of times each line has been Xevaluated, and @samp{values}, a list of the resultant values. Analyzing Xthe database adds two new annotations to various lines in the database: X@samp{zero}, the line was never evaluated, and @samp{constant}, the value Xreturned was the same every time it was evaluated. Note that a line Xevaluated exactly once will be flagged as having a constant value. X XDisplay mode puts up these @dfn{annotations} beside the lisp code in one or Xmore @dfn{annotation windows} which are linked to the @dfn{lisp window} so Xthat all windows scroll together. The functions available for creating Xannotation windows are as follows: X X@table @samp X@item C-c c XOpen an annotation window which highlights code which returned the Xsame value during testing (@samp{tst-display-constant}). X X@item C-c z XOpen an annotation window which highlights code which was never Xevaluated during testing (@samp{tst-display-zero}). X X@item M-x tst-display-open-buffer XCreate a buffer containing the database values for a particular attribute Xover all lines of the lisp buffer. Valid attributes are @samp{count}, the Xcount of how many times that line was evaluated, and @samp{values}, a list Xwith each element the result of one evaluation of that line. X X@item M-x tst-display-open-window XOpen an annotation window onto a buffer created by a prior evaluation Xof @samp{tst-display-open-buffer}. X X@item C-c C-h XOpen a help window showing the key bindings for display mode X(@samp{tst-display-mode-help}). X X@item C-c q XExit display mode (@samp{tst-display-mode-exit}). X@end table X XTypically the first thing you will do after entering display mode is to Xtype @samp{C-c c C-c z} to create two annotation windows which point out Xany lines in the lisp buffer which either were never evaluated or always Xreturned the same value. In the first case you probably need to add to Xyour test script to either call an unreferenced function or exercise the Xother side of a conditional expression. The second case may require some Xinvestigation. One possibility is that the line is something like: X@example X(setq very-important-variable nil). X@end example XThis expression, of course, always returns the same value. Another Xpossibility is that the line was only evaluated once, in which case you Xmight want to add to your test script to hit it again. The third Xpossibility is that you overlooked a parameter when composing your test Xscript. X XIf you want to look at the other annotations in the database, you may do so Xwith the commands @samp{M-x tst-display-open-buffer} and @samp{M-x Xtst-display-open-window}. You must use them in that order, and each one Xwill prompt for an ``attribute name'' which may be either of @samp{count} Xor @samp{values}. X X@section Display Mode---moving within annotation windows X XThe annotation windows are kept in step with the lisp window through Xseveral functions which take the place of the usual cursor movement Xcommands while in display mode. These are described below: X X@table @samp X@item C-n XMove down one line vertically in the lisp window and all associated Xannotation windows. On reaching the bottom of the window, scroll windows Xtogether (@samp{tst-display-next-line}). X X@item C-p XMove up one line vertically in the lisp window and all associated Xannotation windows. On reaching the top of the window, scroll windows Xtogether (@samp{tst-display-previous-line}). X X@item C-v XScroll forward in the lisp window and any associated annotation windows Xkeeping them aligned (@samp{tst-display-scroll-up}). X X@item M-v XScroll backward in the lisp window and any associated annotation windows Xkeeping them aligned (@samp{tst-display-scroll-down}). X X@item C-c l XClear screen and redisplay, scrolling the lisp window and any associated Xannotation windows together to center the line containing point X(@samp{tst-display-redraw}). X X@end table X XThe usual cursor up and down keys are @samp{C-n} and @samp{C-p}, Xrespectively. In display mode these move point in all annotation windows Xsimultaneously so that when the limits of the screen are reached all Xwindows will scroll together. Similarly the scroll-up and scroll-down keys X@samp{C-v} and @samp{M-v} are rebound in display mode to functions which Xkeep track of what annotation windows are open and scroll them in step with Xthe lisp buffer. It is still possible for the windows to get out of step X(e.g. after using @samp{M-<}), so the @samp{C-c l} key will resynchronize Xall annotation windows while recentering the line containing point just as Xthe @samp{C-l} key does for a single window. X X@section Batch Display of Analysis X XQuite separate from the display mode is a display function that is designed Xto give a concise summary of test coverage without your interaction. This Xfunction can be run in batch or interactively. (It was originally intended Xfor only batch operation, hence the name.) X X@table @samp X@item M-x tst-display-batch XGenerate a @dfn{compilation style} buffer containing @dfn{zero} and X@dfn{constant} analyses from the database. X@end table X XYou need not be in display mode to use @samp{tst-display-batch}. You are Xmost likely to use it in a test script run from batch mode to dump out a Xsummary of test coverage at the end of a run. However it is also useful Xfrom interactive mode because it takes advantage of the Emacs function X@samp{C-x`} (@samp{next-error}), often used to view compiler error Xmessages. The first invocation of @samp{C-x`} parses the error messages in Xthe buffer named @samp{*compilation*} then places point in one window on Xthe line of code referenced by the error message shown at the top of the Xother window. Successive @samp{C-x`} keystrokes advance to successive Xerror messages and the corresponding lines in the code buffer. X XThe @samp{M-x tst-display-batch} command writes into the X@samp{*compilation*} buffer a line for every line in the lisp buffer that Xhas either a @samp{zero} or @samp{constant} annotation. Subsequent uses of X@samp{C-x`} advance to the next error and the corresponding line in the Xlisp buffer. X X@section The Example X XThe following is the output of the evaluation of @samp{tst-display-batch} Xin our example test script. Notice that some deficiencies in the test Xscript are pointed out: error conditions were not exercised (see lines X121-122 and 134-135 in Appendix A); and not enough different input texts Xwere ``boxed'' to really stress the package under test (e.g. line 40, input Xtext always same width). X X@example X# Test analysis of box.el X# (lines which were never evaluated during tests or returned X# the same value every time they were evaluated.) Xbox.el:31== nil Xbox.el:33== nil Xbox.el:34== nil Xbox.el:35== nil Xbox.el:37== 1 Xbox.el:38== 0 Xbox.el:39== nil Xbox.el:40== 41 Xbox.el:41== nil Xbox.el:42== nil Xbox.el:43== 42 Xbox.el:47== 44 Xbox.el:49== 1 Xbox.el:50== nil Xbox.el:51== nil Xbox.el:52== nil Xbox.el:53== nil Xbox.el:55== nil Xbox.el:56== nil Xbox.el:57== nil Xbox.el:58== nil Xbox.el:59== nil Xbox.el:62== nil Xbox.el:63== nil Xbox.el:64== nil Xbox.el:65== nil Xbox.el:67== nil Xbox.el:68== nil Xbox.el:69== 1 Xbox.el:70== 12 Xbox.el:71== nil Xbox.el:72== nil Xbox.el:73== nil Xbox.el:74== 12 Xbox.el:75== nil Xbox.el:80== nil Xbox.el:91== nil Xbox.el:93== nil Xbox.el:94== nil Xbox.el:95== nil Xbox.el:109== #<marker at 6 in box.junk> Xbox.el:115== nil Xbox.el:116== t Xbox.el:121== NEVER->> Xbox.el:122== NEVER->> Xbox.el:128== nil Xbox.el:129== nil Xbox.el:134== NEVER->> Xbox.el:135== NEVER->> Xbox.el:140== nil Xbox.el:141== nil Xbox.el:143== nil Xbox.el:144== t Xbox.el:145== NEVER->> Xbox.el:147== t Xbox.el:149== nil Xbox.el:150== nil Xbox.el:151== nil Xbox.el:153== nil Xbox.el:154== nil Xbox.el:157== nil Xbox.el:159== nil Xbox.el:160== #<marker at 6 in box.junk> X X@end example X X@node running, epilogue, displaying, top X@chapter Running Test in Batch Mode X X@section Preparation X XBefore running a set of tests, you must prepare the following items: X@itemize @bullet X@item XA package to test. X@item XA test script, usually written as a single function. X@item XA set of precondition states---one for each test (although many Xtests may share the same precondition). X@item XA set of expected postcondition states---one for each test (some Xsharing is possible). X@end itemize XTest scripts are discussed in the next section. X XYou will probably want to use the state-capturing functions (e.g., X``tst-capture-state'', ``tst-write-state-to-file'') to prepare and save Xstates in files. In doing this, strive for minimality of states. That is, Xavoid complicating the states with extra components, particularly buffers Xand windows, that do not contribute to the functionality being tested. XThis will make it easier to read and comprehend the testing states, and Xwill result in more efficient test scripts. (The instrumentation and Xanalysis components of Test are designed to assist you in discovering the Xinadequacies of your test scripts. It is best to start with too little Xtesting, and add additional tests as the analysis dictates.) X XBelow is an example scenario for preparing the states used in a testing Xscript discussed later. Note that the functions would be invoked Xinteractively, even though they are shown in ``program invocation'' style. X@example X(load "test.el") X(load "box.el") X(find-file "sample") X... go to an appropriate location ... X(set-mark) X... go to an appropriate location ... X(tst-capture-state-to-file "pre-box") X(box-region) X(tst-capture-state-to-file "exp-box-1") X(unbox) X(tst-capture-state-to-file "exp-unbox-1") X(box-region t) X(tst-capture-state-to-file "exp-box-2") X(unbox t) X(tst-capture-state-to-file "exp-unbox-2") X@end example XNote that in this scenario the expected result of applying a function is Xcreated by applying the function to the precondition state. It is hard to Ximagine how the test could fail, but it might for unexpected reasons. A Xbetter method of creating the test states is to use an independent method, Xsuch as repeated application of simpler functions (e.g., ``insert'', X``next-line''). Still, ``safe'' tests, such as that shown above, are Xuseful for regression testing. X X@section Batch Test Scripts X XA test run usually consists of the following steps: X@enumerate X@item XRead testing states from files. X@item XInitialize the testing environment: X@enumerate X@item XFind the object package (the code to be tested). X@item XInstrument the package. X@end enumerate X@item XRun each test: X@enumerate X@item XAchieve the precondition state of the test. X@item XExecute the function to be tested. X@item XCapture the postcondition state. X@item XCompare the postcondition state to the expected postcondition state. X@end enumerate X@item XSave the results of testing in a file. X@item XAnalyze the testing (filter the collected data) and save the results. X@end enumerate XNote that a set of tests may reuse testing states, especially the Xpreconditions of tests. That is why it is wise to read all of the needed Xtesting states from files first. Also, it is good style to minimize state Xchanges during testing (except for the execution of tested functions, of Xcourse), so that the test script may be modified without unforeseen side Xeffects. X XBelow is an example test script for testing functions ``box-region'' and X``unbox'' in package ``box.el''. This script does not contain enough Xtests, which the instrumentation should expose. X X@example X(load "test.el") X X(defun script () X (let (post-state pre-box exp-box-1 exp-box-2 X pre-unbox exp-unbox-1 exp-unbox-2) X ; Load states from files X (tst-read-state-from-file 'pre-box "pre-box") X (tst-read-state-from-file 'exp-box-1 "exp-box-1") X (tst-read-state-from-file 'exp-box-2 "exp-box-2") X (tst-read-state-from-file 'pre-unbox "pre-unbox") X (tst-read-state-from-file 'exp-unbox-1 "exp-unbox-1") X (tst-read-state-from-file 'exp-unbox-2 "exp-unbox-2") X ; Instrument package X (find-file "box.el") X (tst-instrument) X ; Initialize test environment X (find-file "sample") X ; Tests X ; TEST box-1 X (tst-achieve-state pre-box) X (box-region nil) X (tst-capture-state 'post-state) X (tst-equ-state post-state exp-box-1) X ; TEST box-2 X (tst-achieve-state pre-box) X (box-region t) X (tst-capture-state 'post-state) X (tst-equ-state post-state exp-box-2) X ; TEST unbox-1 X (tst-achieve-state pre-unbox) X (unbox nil) X (tst-capture-state 'post-state) X (tst-equ-state post-state exp-unbox-1) X ; TEST unbox-2 X (tst-achieve-state pre-unbox) X (unbox t) X (tst-capture-state 'post-state) X (tst-equ-state post-state exp-unbox-2) X ; Results of tests X (set-buffer "*equal-log*") X (save-file "equal-log-sample") X ; Analysis of testing X (tst-analyze) X (tst-display-batch) X ) ; let X) ; defun script X@end example X X@section Batch Invocation of Test X XTo invoke the test script from batch, use the following Unix command: X@example X% gnuemacs -batch -l script.el -f script -kill & X@end example XNote that the test script explicitly loads ``test.el'' at the beginning Xof ``script.el''. X X XAn instrumented package runs considerably slower than an uninstrumented Xpackage. It is a good idea to test your script without instrumentation X(and probably without many of the tests). Once you are satisfied with the Xscript, run it at lower priority and/or at non-peak hours to avoid Xinconveniencing other users. X X@section Advanced Batch Use -- Filtering X XThe state information available for ``capture'ing and ``achieve''ing is Xusually more than needed for any particular test. You can improve the Xperformance of testing by filtering out the unneeded components of states. XThere are mechanisms for doing this before and after testing: X@itemize @bullet X@item XThe ``capture'' functions use global options to determine the Xcomponents to capture. X@item XThe ``achieve'' functions are similarly parameterized. X@item XThe ``equality'' functions use global options to determine which components Xto compare. Also, they can be weakened (i.e. return ``true'' more often) Xthrough the use of hooks and replacement functions. X@item XThe ``analysis'' functions reduce the instrumentation data to two special Xcases: lack of evaluation and ``constant value across testing''. X@item XThe ``*equal-log*'' buffer may be viewed in ``outline'' mode, with Xuninteresting cases suppressed through elision. X@item XThe batch display function produces output that may be viewed with the X``next-error'' function of ``compilation''. X@end itemize XIn using these filters you should be aware that too much filtering defeats Xthe purpose of testing. X X@node epilogue, example, running, top X@chapter The Epilogue X X@section How to Extend the Package X X@subsection Equality Tests X XIf you want to extend the equality package to compare other aspects of your Xenvironment, simply write your own comparison function and add it to the X'function-vector' for the appropriate area. For example, if you were Xinterested in comparing the @code{foobar} attribute of buffers, first write Xa function, @code{tst-equ-foobar}, and then add it to the list of functions Xexecuted for a buffer, @code{tst-equ-buff-state-functions}. X XSimilarly, if you wanted to test the @code{foo} attribute of a state, add Xthe new function to the list of functions executed for a state, X@code{tst-equ-state-functions}. X XYou can also extend the equality tests by the use of hooks. The method is Xdefined in more detail in the section on Inequality. X X@subsection Instrumentation X X@subsection Display Functions X XThe interactive display mode attempts to provide the fiction of annotation Xwindows which are part of the code window. In retrospect it may be that Xsimply inserting the text into a new buffer along with the code would be as Xuseful. It also may be that the batch style report in conjunction with the X``compilation'' error parsing is just as useful in practice. X XThere are certainly other types of annotation which could usefully be Xdisplayed, like the number of times each line was executed, etc. X XIt might make sense to bind @samp{tst-display-batch} to a key in X@code{test-mode}. It also might make sense to remove the binding for X@code{tst-analyze} and call it only from within the display functions. X X@subsection Annotation Functions X XThe annotation database is accessed twice every time an instrumented line Xof code is evaluated. This code contributed substantially to the slow-down Xof instrumented code and time spent making it more efficient would be Xrewarding. X X@subsection Analysis Functions X XIf you want to add further functions to the Analysis Package, you will have Xto modify the main function, ``tst-analyze'', which invokes the individual Xanalysis functions. It currently invokes ``tst-anl-zero-counts'' and X``tst-anl-constant-values''. Your new function should use the same idiom Xas these functions, i.e., use ``tst-ann-get-lines'' to retrieve the list of Xlines for which annotation holds information and then use ``mapcar'' to Xapply your single line analysis function to each line's data. You can then Xuse ``tst-ann-put'' to store your results. X X@node example, , epilogue, top X@appendix The Complete Example X@include example SHAR_EOF if test 60887 -ne "`wc -c < 'test.texinfo'`" then echo shar: "error transmitting 'test.texinfo'" '(should have been 60887 characters)' fi fi exit 0 # End of shell archive -- Rich $alz Cronus Project, BBN Labs rsalz@bbn.com Moderator, comp.sources.unix sources@uunet.uu.net