Data Structures and Algorithms

Lab 1: Testing

Due on Sunday, January 31st at 11:59 PM. This is an individual lab. You are to complete this lab on your own, although you may discuss the lab concepts with your classmates. Remember the Academic Integrity Policy: do not show your code to anyone outside of the course staff and do not look at anyone else’s code for this lab. If you need help, please post on the Piazza forum or contact the instructor or ninjas. If you have any doubts about what is okay and what is not, it’s much safer to ask than to risk violating the Academic Integrity Policy.

Overview

This lab will focus on automated testing. In this lab, you will learn about:

You can begin by cloning your code repository at git@github.swarthmore.edu:cs35-s16/lab01-<your-username>. Recall that Lab 0 gave instructions for cloning Git repositories from the Swarthmore GitHub.

Testing Your Programs

Television Test Pattern

The process of writing a program can be broken into a few steps:

  1. Figure out what you want (e.g. read your lab assignment)
  2. Plan how you will teach the computer to solve your problem (i.e. design an algorithm)
  3. Write your program as source code
  4. Test your program to make sure that it works correctly
  5. Repeat the above steps whenever you find bugs or other mistakes

This lab focuses on step 4 above. You should always run your program to make sure that it works correctly in a variety of situations. This requires running your program several times and inspecting the output, which can be exhausting. If you change your program to fix a bug, your change might introduce a new bug. Ideally, you would test every different scenario you could imagine every time you change your program, but that would be tedious and time-consuming.

Conveniently, computer programming is a good solution for tedious, time-consuming tasks. Instead of testing our program manually, we’ll write a tiny program to test our code for us. There are many different forms of testing for software in general; the approach we will use here is called unit testing. We’ll be using an open-source library called UnitTest++ to write our tests.

UnitTest++

In general, unit testing libraries are specific to an environment or language. UnitTest++ is a library which simplifies the process of unit testing in C++. Although UnitTest++ provides a variety of testing operations (which are documented here), we only require a few of them.

Sets

Venn Diagram

A set is a simple data type similar to a list. Both sets and lists can hold multiple values. However, lists and sets differ in that:

In this lab, you will work with a set interface defined in the header file set.h. You should look at that file. It contains documentation describing the behavior of the Set class. The set.h file is a header file: it contains the interface describing how the class can be used but not the implementation describing what it does. This is important: it means we can write code using the Set without having to think about how it works.

The remainder of this section gives an example of how the Set class might be used.

First, we can create a Set object by declaring a variable of that type.

Set s;

This syntax is a little different from Python or Java and has different meaning: the Set we are creating now will be destroyed at the end of the current function, just like other local variables. It’s important to note that this calls the constructor of the Set class on s, so it’s ready to be used.

Now that we have an empty set, let’s add some numbers to our set now using the add method.

s.add(4);
s.add(6);
s.add(8);

We can determine whether a number is in our set by using the contains method.

s.contains(4); // returns true
s.contains(5); // returns false
s.contains(6); // returns true

We can also determine the number of elements in our set using the size method.

s.size(); // returns 3 (because the set contains 4, 6, and 8)

Now let’s remove a number using the remove method.

s.remove(4); // the set now contains just 6 and 8
s.size(); // so this call will return 2
s.contains(4); // and this call will return false
s.contains(6); // but this call still returns true

Nothing is wrong with adding an existing element or removing an absent one; they just don’t do anything.

s.remove(4); // we already removed 4, so this does nothing
s.remove(9); // s never contained 9, so this does nothing as well
s.add(6); // s already contains 6, so this also has no effect

Of course, we can create more than one set.

Set s2;
s2.add(1);
s2.add(3);

The Set class also has methods to allow two sets to be used together. For instance, add_all will add all of the elements from another set.

s2.add_all(s);
s2.contains(6); // returns true: s2 now contains 6 because s did
s2.contains(4); // returns false: s2 still doesn't contain 4 because s didn't
s.contains(1); // returns false: s wasn't changed and still only contains 6 and 8

We can also use remove_all to remove all of the elements from another set.

s.remove_all(s2); // since s2 contains 1, 3, 6, and 8, all of those would be removed (if they exist)
s.size(); // so now s should be empty; this call returns 0

At the end of this function, the s and s2 objects will be destroyed because they were statically allocated. We will cover during lecture precisely what this means.

Your Assignment

The implementations directory of your Git repository for this lab contains many implementations of the interface given in set.h. Each implementation is stored as an object file (e.g. set04.o). One of these implementations is correct; the rest are intentionally broken in a variety of ways. We will give you descriptions of the different set implementations (but we won’t tell you which description goes with which .o file). Your job will be as follows:

Setting Up

Remember from the last lab that your assignment will be submitted by updating the contents of your repository on the Swarthmore GitHub. To get started, you need to clone that repository into your home directory on the CS network:

git clone git@github.swarthmore.edu:cs35-s16/lab01-<your-username>.git

Your initial repository includes a Makefile which you will use to build your code. The first time you run make, it will perform a series of operations that you won’t have to perform again. Go ahead and run make now to get that out of the way.

Testing the Sets

You will write your tests into the file test_set.cpp. Once you have done so, you can compile that file, link it with one of the set implementations, and then run the resulting program. Ordinarily, this could look something like the following:

$ # This next line compiles test_set.cpp into test_set.o
$ c++ -c test_set.cpp
$ # This next line links test_set.o with a set implementation and with UnitTest++
$ c++ -o test_set00 test_set.o implementations/set00.o unittest-cpp/CMakeFiles/UnitTest++.dir/UnitTest++/*.o unittest-cpp/CMakeFiles/UnitTest++.dir/UnitTest++/Posix/*.o
$

That’s rather tedious, of course, so we’ve added rules to the Makefile to help you build your test programs. Instead of the above:

For instance, if I want to run my tests against implementation 6, I could run:

$ make test_set06
c++ -c -o test_set.o test_set.cpp
c++ -o test_set06 test_set.o implementations/set06.o "unittest-cpp/CMakeFiles/UnitTest++.dir/UnitTest++/"/*.o "unittest-cpp/CMakeFiles/UnitTest++.dir/UnitTest++/"/Posix/*.o
$ ./test_set06
Success: 1 tests passed.
Test time: 0.00 seconds.
$

The initial test_set.cpp that you have been provided contains only one test, which creates a set and then destroys it. This is, of course, not very interesting and you have some work to do here. Normally, you would have to invent your own tests to be sure that your code is correct. This involves thinking about behavior your code should (or shouldn’t) have and then writing tests accordingly. This time, however, you will know the behavior of the different implementations; you just don’t know which one is which. So it will be sufficient for you to write tests based on that behavior. Here are descriptions of each of the set implementations you have been provided. Each description is accompanied by a name.

Identifying the Sets

In addition to writing the tests described above, you will submit a file named matches.txt which will contain a series of matches in the following format:

set00: correct
set01: starts_containing_4
set02: size_zero
set03: has_maximum_size
...

That is, if you believe that set00.o is the correct set implementation, you write a line into the matches.txt file containing the set’s number (e.g. set00) and its name (e.g. correct). Add matches.txt to the same directory in your repository as the test_set.cpp file. If your file is not in this format, you will lose points!

Deliverables

To summarize, you will be submitting two files for this assignment:

Please refer to Lab 0 for the appropriate git commands. Don’t forget to commit, push, and then check the Swarthmore GitHub site to make sure everything turned out okay!