This file is divided into three sections:
Each project will be tested using automated testing software. You have access to the same testing infrastructure which will be used to mark your projects.
Associated with each class you are required to write will be a tester class and (usually) a driver program. The driver uses your class and the tester class to create an interactive environment where you can enter commands to use and test the class you wrote.
Suppose you have written the classes SingleList (saved in the file SingleList.h) and SingleNode (saved in the file SingleNode.h). Together with the Exception.h file you have already used, you would also download the files SingleListTester.cpp, SingleListTester.h, and ece250.h.
Compile the project into an executable and run the executable.
Note to MS Visual Studio users: only allows one file per project to have a int main(). Simply do not add more than one .cpp file to the project and when you need to test the other driver, remove the one currently included in the project and add the other.
The executable driver produces a prompt. At this point, you can enter a command. The available commands are listed at the top of the SingleListTester class, and for convenience, that portion of the file is listed here:
/**************************************************** * void process() * * Process the current command. For singly-linked lists, these include: * * Constructors * * new Constructor create a new instance of the class being tested * delete Destructor call delete on the class currently being tested * * Accessors * * size n size test if size() == n * empty b empty test if empty() == b * front n front test if front() == n * back n back test if front() == n * head0 head test if head() == 0 * tail0 tail test if tail() == 0 * member n b member test if member( n ) == b * * head head tests if head() != 0 and if so, creates * a SingleNodeTester with the head * use exit to return to testing the SingleList class * tail tail like head(), but tests tail() * with a SingleNodeTester - use exit to return * * Mutators * * push_front n push_front calls push_front( n ) * push_back n push_back calls push_back( n ) * pop_front n pop_front tests if pop_front() == n * remove n b remove tests if remove( n ) == b ****************************************************/
In all cases, n or m represents an integer while b reprsents either 0 (false) or 1 (true).
Suppose you have implemented some of the functions in your class SingleList class and you would like to test them by doing the following:
For good measure, we will also check what happens if we check if 50 is at the front of the linked list. Anything in red is text which you would type:
C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe Starting Test Run 1 % new Okay 2 % push_front 38 Okay 3 % front 38 Okay 4 % push_front 42 Okay 5 % front 42 Okay 6 % push_back 71 Okay 7 % front 42 Okay 8 % front 50 Failure in front(): expecting the value '50' but got '42' 9 % delete Okay 10 % exit Okay Finishing Test Run Memory allocated minus memory deallocated: 24
Each time the operation is successful, Okay is printed. Otherwise, a useful error message is printed.
Instead of alwasy interacting with the interpreter, you can simply store all the commands in a file and redirect the file to the executable.
Create a file called test01.txt and place into this file all of the commands you entered manually above (though exit is not necessary):
new push_front 38 front 38 push_front 42 front 42 push_back 71 front 42 front 50 delete
At the command line, you can now type:
> Project1a.exe < test01.txt
The < tells the operating system to behave as if the contents of the file text01.txt were being entered interactively. This is a process called redirection.
The output of this process is:
C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe < text01.txt Starting Test Run 1 % Okay 2 % Okay 3 % Okay 4 % Okay 5 % Okay 6 % Okay 7 % Okay 8 % Failure in front(): expecting the value '50' but got '42' 9 % Okay 10 % Exiting... Finishing Test Run Memory allocated minus memory deallocated: 24
At this point, we notice one critical bug: the last line indicates that 24 bytes were allocated, but not unallocated when the delete function was called.
If we examine the destructor, we get an idea as to what went wrong:
template <typename Type> SingleList<Type>::~SingleList() { }
Each time we pushed something into the singly-linked list, we needed to create a new instance of a SingleNode class. Because we did so, in the destructor, we must delete each of those nodes. If we would fix this, the last line of the output would be:
Memory allocated minus memory deallocated: 0
One thing which is very useful is testing boundary cases. For example, suppose you add one object into a singly linked list and then remove it again. In this case, both the head and the tail should be 0. Thus, we would add an object, remove it, and then check that both the head and the tail are 0. We could do this by running the following sequence of commands:
new push_front 23 remove 23 1 head0 tail0 delete
You could save this to a file test02.txt and you could test this until the output is:
C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe < test02.txt Starting Test Run 1 % Okay 2 % Okay 3 % Okay 4 % Okay 5 % Okay 6 % Okay 7 % Exiting... Finishing Test Run Memory allocated minus memory deallocated: 0
It can become very tedious typing push_front twenty times, so simplify this, you can use !! to represent the previous command. You may also use !n to represent the nth command. In this example, !! always represents the previous command, while !5 represents the 5th command, i.e., pop_front.
C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe Starting Test Run 1 % new Okay 2 % push_front 12 Okay 3 % !! 34 Okay 4 % !! 56 Okay 5 % pop_front 56 Okay 6 % front 34 Okay 7 % !5 34 Okay 8 % !! 12 Okay 9 % size 0 Okay 10 % delete Okay 11 % exit Okay Finishing Test Run Memory allocated minus memory deallocated: 0
Given a class ClassName which you would like to test, you would create a derived class of the Tester class. A simple driver routine would create an instance of this derived tester and call the member function void run(). Each of these features is linked to in the left column, but is described here more thorougly: