CS2201 Assignment 0

CS2201
Assignment No. 0
Purpose: This assignment has several goals:
1. This is a relatively simple assignment, meant to get you back into programming after the semester break.
2. Make sure you can edit/compile/run C++ code in whatever IDE you will be using this semester (preferably CLion). 3. Gain experience in using and manipulating objects in C++.
4. Gain experience in writing test code that will thoroughly test a C++ class.
5. Make sure you can correctly submit code for grading via Brightspace.
You will be provided a C++ class that represents some type of object and you will write a program that exercises that class as fully as possible. Note: your task is only to test the supplied class; not to implement the class.
Background on DNA, Restriction Enzymes, and PCR:
This background is interesting, but not really needed to do the assignment. There are some good stories here, but if you want to get to the assignment, you can skip this stuff.
In this assignment you will be provided a class that simulates cleavage (cutting) of DNA by restriction enzymes. DNA is made up of sequences of molecules known as nucleotides that are linked together to form a DNA strand. Biochemists use the letters ‘A’, ‘C’, ‘T’, and ‘G’ (standing for adenine, cytosine, thymine, and guanine) to represent a linked sequence of nucleotides within a DNA strand. Restriction enzymes are molecules that recognize and cut very specific “target” nucleotide sequences. These target sequences are commonly referred to as restriction sites.
Three scientists shared the Nobel Prize in 1978 for the discovery of restriction enzymes. They’re also an essential part of the process called PCR polymerase chain reaction which is one of the most significant discoveries/inventions in chemistry and for which Kary Mullis won the Nobel Prize in 1993.
You can see animations and explanations of both restriction enzymes and PCR at DnaTube and Cold Spring Harbor Dolan DNA Learning Center.
Restriction Enzymes PCR: Polymerase Chain Reaction
(source: http://www.roche.com/pages/facets/1/pcr1.jpg
(source: http://www.astbury.leeds.ac.uk/gallery/leedspix.html)
Kary Mullis, the inventor of PCR, is an interesting character. To see more about him see this archived copy of a 1992 interview in Omni Magazine, this 1994 interview as part of virus myth, his personal website which includes information about his autobiography Dancing Naked in the Mind Field, though you can read this free Nobel autobiography as well.

The simulation is a simplification of the chemical process but provides us a nice starting point for our exploration of C++ and also provides us with a basis for future assignments.
The DNA_Strand class:
This class is a simplification of the chemical process but provides an example of the DNA manipulation using simple arrays. The provided class uses a static array containing character, such as the letters ‘A’, ‘C’, ‘T’, and ‘G’, to represent the sequence of nucleotides within a DNA strand (though not limited to only the letters ‘A’, ‘C’, ‘T’, and ‘G’).
Sample representation of a DNA molecule: ACTTGATTGGGTTGCTTGCC???
Note that the array may be larger than the strand that we are representing, and thus there may be unused array elements after the nucleotides within the strand [this is known as a partially-filled array; in this example we have an array that can hold 23 characters which is currently only holding a 20 character strand, the question marks indicate unused array elements whose values we don’t know or care about].
Cleavage by a restriction enzyme will simply mean removing a specified sequence from our DNA strand. Cleaving requires a target nucleotide pattern. The sequence to be removed will be the nucleotides that reside between matching pairs of the target pattern. A cleave will remove all nucleotides beginning after the first occurrence of the target pattern and continue through the end of the second (matching) target pattern. The class provides 2 functions cleave and cleaveAll, which will implement cleaving in 2 different forms. The cleave method will cleave only the first such sequence while cleaveAll method will remove all such sequences between matching pairs within the DNA strand.
Thus, for example, if we invoke cleave(“TTG”) on the above DNA strand, we would remove the first set of highlighted characters and the resultant DNA strand will be:
ACTTGGGTTGCTTGCC??????? Notice how the data was shifted down in the array to fill the hole created by the deleted sequence.
In comparison, if we invoke cleaveAll(“TTG”) on the original DNA strand above, we would remove both sets of highlighted characters and the resultant DNA strand will be:
ACTTGGGTTGCC???????????
The nucleotides in our DNA are character values, so the class uses an array of type char. The array is of size MAX_DNA (a constant variable set to 50 – a value too small for real DNA but it makes our testing easier) and so we will be limited to holding DNA with a maximum number of nucleotides of MAX_DNA. The class also has a private instance variable called mySize which will keep track of the size of the strand (i.e., how many elements we are actually using of the partially- filled array).
The Assignment:
You will be supplied three files:
• DNA_Strand.h: the declaration of the DNA_Strand class (do not change)
• DNA_Strand.cpp.obj or DNA_Strand.cpp.o: this is the compiled object code of the DNA_Strand class which
implements all the class methods [it was produced from a properly working DNA_Strand.cpp file] Note that this file contains binary information – if you attempt to look at it in the editor it will be gibberish and you may corrupt it causing it to no longer work. (do not change)
• DNAtest.cpp: the test program. Your job is to add code to the DNAtest.cpp file to fully test/exercise the DNA_Strand class.

You will be supplied the class declaration file: DNA_Strand.h. The file contains the declaration of a set of functions to manipulate static arrays representing DNA. You will also be supplied a compiled object file, DNA_Strand.cpp.obj (or DNA_Strand.cpp.o on MacOS), which implements all the functions [it was created from a properly working DNA_Strand.cpp file]. You will also be provided with an initial test program: DNAtest.cpp. Your job is to add code to the DNAtest.cpp file to fully test/exercise the DNA_Strand class to ensure it works as expected. This is known as test- driven development: we write code to test that a class works as expected, and afterward we write the class such that it passes all tests (the only difference is that I am giving you working code so that you can see if your tests are correct or not). Note: your task is to only test the DNA_Strand class, not to implement the DNA_Strand class. All the functions that you are to test are fully described in the DNA_Strand.h file. Note: you are not allowed to change the DNA_Strand.h file.
Implementation details:
Here are a few notes that might be helpful:
1. You are to download a zip file that is provided with this specification. You need to download the correct zip file
for your platform (either Windows, MacOS for an Intel CPU, or MacOS for an Apple CPU). The zip file contains a CLion project that includes starter code for this project. You must unzip/extract the files before you work on them. Once you unzip the file, you can open the project by starting CLion, then specify that you want to “Open Project”, and then navigate to the folder you just extracted. When you open the project, let CLion do its initialization work and load symbols. The code as provided compiles cleanly (no errors or warnings) and executes successfully – though it only performs minimal testing in its distributed form. Again, you must unzip/extract the files before you work on them.
2. The test code that you write should be fully automated, as demonstrated in the small segment of provided test code. That means your test code should not depend upon reading any input from a user nor should it require the user to visually inspect any output. Relying on the user to enter all special cases to be tested is prone to omissions. Plus anyone else who uses such test code would not know what data to enter so that the class is fully tested.
3. You will likely be performing some operations with C++ strings. C++ string operations are described here. You will only need a few of the available operations in this assignment, such as length, at (or use [ ]), assignment, equality operator or compare method, substr, and maybe others.
4. The length() method of the string class returns a value of type size_t (an unsigned integer type). We also use variables and parameters of type size_t whenever we expect the value to be non-negative (e.g., parameters that represent an array index are declared to be size_t variables). The compiler may give you conversion warning messages if you attempt to assign/compare these values to a value of type int. Your homework submissions are expected to have clean compiles (no errors or warnings). To eliminate this particular warning, you can cast the size_t values to an int, or cast the int values to type size_t if you know the integer values are not negative. Note: all grading will be done with CLion and the clang compiler, which may produce different warning & error messages than other compilers – if you are developing with something other than CLion/clang, it is your responsibility to ensure you code compiles cleanly with CLion/clang.
5. You will need to test the Boolean value that is returned for the isEqual() method. C++ defines two literal constants true and false – please note that they are all lowercase. Please remember to use Boolean-zen while writing your code.
6. The DNA_Strand.h specifies that some methods throw an exception if someone attempts to access a part of your DNA_Strand that is not within the bounds of the DNA strand that you are currently representing. When an exception is thrown it will cause your program to stop executing if the exception is not handled. You will want to test the class to make sure exceptions are thrown appropriately, so you need to know how to handle the exceptions. To handle exceptions you use what is known as try-catch blocks, which can catch the thrown exceptions. The distributed DNAtest.cpp file contains a try-catch block that you can duplicate to test the exception throwing capabilities of the DNA_Strand class. Your test program must use try-catch blocks whenever it expects an exception to be thrown – this will allow your program to continue executing. You should write a new try-catch block for each exception you are testing. More information on C++ exceptions can be found in chapter 21 of our text (zyBooks).
7. Even though this class is designed to represent DNA strands, the class does not restrict the user to only using the characters ‘A’, ‘C’, ‘G’, and ‘T’; rather it will allow any characters to be stored in the DNA strand.
8. Note that if you do not understand how a method of the class is supposed to act from its description/specification, then you can simply try it out – you were supplied a working class as a part of the assignment.
9. Every semester we have issues with students who submit code that fails to compile with the grading script even though the code compiles on their machine. If you correctly open (not import) the provided CLion project, this

should not be an issue. But just to make sure, please check your CMakeLists.txt file and ensure that it specifies
these flags for your C++ compiler: -Wall -Werror -Wextra -pedantic -pedantic-errors
10. To be perfectly clear, your job in this assignment is to fully test the DNA_Strand class to the best of your ability.
Your job is not to write the DNA_Strand class – that code has been provided to you in the form of a compiled object file.
Submission for grading:
When you have completed your work on this assignment, please submit your DNAtest.cpp file for grading. Submit ONLY the single source file – please do not submit a zip file containing your entire project, and do not submit DNA_Strand.h or the DNA_Strand object file. You can submit the file by visiting the assignment page in Brightspace (click on the assignment name), scroll down to the “Submit Files” section, and add the file by clicking on the “Add a file” button and finding the file to attach.
After submitting your homework, it is good practice to verify your submission. Revisit the assignment page in Brightspace and make sure that your file was successfully submitted. Then click on the file to open it up so that you can verify that you submitted the correct file, as opposed to some older version of the file. It is your responsibility to ensure the correctness of your submission – this is true for all assignments.
Grading:
This project is worth 25 points (half of a normal assignment). Your grade on this project will be based on the thoroughness of your testing performed in the DNAtest.cpp file. Please make sure that your code compiles without errors or warnings, and it runs to completion without prematurely terminating (say, due to an uncaught exception).
You should also review the syllabus regarding the penalties for late programming assignments.
Note that we never grade test code for good programming style. However, it is to your benefit to use good style. We will be using this test program for several assignments, and you will need to update it to test new/different behaviors. Such updates are much easier when the test program is written with good style, using separate functions to test different methods of the class. Past students have complained that updating the program was very hard for them since their code was such a mess (which they thought did not matter since the code was not graded on style).
[There is more information below on opening provided projects in CLion.]

=============================================================================
Opening a CLion project:
1. Unzip the provided zip file. This will create a folder named project0-Windows or project0-MacOS-Intel or project0-MacOS-M1 that contains a set of files.
2. Start up CLion. If it brings up an existing project, close that project down by selecting “Close Project” from the File drop-down menu. This will return you to the CLion welcome screen:
3. From the CLion welcome screen, select “Open Project”
4. Navigate to the project0-Windows or project0-MacOS-Intel or project0-MacOS-M1 folder that you unzipped in step 1. The folder should be displayed slightly differently than other folders since it contains a CLion project. Select the folder and press OK.
5. At this point, CLion will open up and display to you the DNAtest.cpp file. At the bottom of the screen you will see status messages as it loads necessary symbols, etc. Do not do anything until the status messages stop. When the status messages stop, it should look something like this:

6. To verify that you have open the project correctly, please click on the CMakeLists.txt tab in the editor pane and check to see that the following lines are included (these lines set important compiler flags):
7. You now should be able to build the project and then run it (remember that you should always do those two steps separately).
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -pedantic -pedantic-errors”) set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -fno-limit-debug-info”)

=============================================================================
Addendum:
[This information was written by a past TA – it is optional but helpful]
Here is some additional material on testing that may make your task of testing a bit easier: Testing:
There is no question that testing the code we write is important. Some communities deem it so important, in fact, that they write their tests before they write the code that is to be tested. Test Driven Development (TDD for short) has exploded in popularity over the last couple of years and embodies this principle. Properly written tests give us the peace of mind that our code works but they can offer so much more. Software changes constantly. In fact, most of the cost of software development is due to maintaining and updating existing programs instead of writing new ones. If we are in charge of adding a new feature to an existing project, we would like to avoid introducing bugs in the process. This is the major benefit of TDD. The initial time investment necessary to write the test suite pays for itself hundred-fold when you’re modifying your implementation. After every change you make you can simply run the tests again and be sure that you didn’t break anything in the existing code.
In order to get the most out of TDD, however, out test suites themselves must be written so that they are readable, extendable, and isolated. It is customary to provide multiple test functions that test different cases of a single functionality. The naming convention for our test functions is such that we should be able to tell exactly what is being tested from the name alone.
Below are a couple of the Project 0 tests written to follow the testing structure.
const std::string PASS(“pass”);
//function prototypes
std::string testSizeEmpty();
std::string testToStringNonEmpty();
int main() {
std::cout << “DNA empty size: ” << testSizeEmpty() << endl;
} std::cout << “toString nonEmpty: ” << testToStringNonEmpty() << endl;
std::string testSizeEmpty() {
DNA_Strand dna1;
if (dna1.size() == (size_t)0) {
return PASS;
} else {
} } return “Wrong value returned: ” + std::to_string(dna1.size());
std::string testToStringNonEmpty() {
std::string ipStr = “ABCCTG”;
DNA_Strand dna(ipStr);
//toString should return the contents as a string
if(dna.toString()==ipStr) {
} return PASS;
else {
} } return “Wrong string returned: ” + dna.toString();

As you can see, this style of testing is extremely modular and easy to follow. Moreover, running and interpreting the tests is trivial. You get a nice, table-like output that tells you if a test passed or why it failed. You can easily add more tests or disable a couple (maybe if you are debugging) by simply commenting out the corresponding line in the main function. There is one weakness with the current setup however. Forcing the tests to return a string object makes concatenating output with the streaming operations rather difficult. We can modify our approach by passing a stream object to each function directly and moving some of the formatting responsibility.
Here is what the same test code looks like with this new approach:
const std::string PASS(“pass”);
//function prototypes
void testSizeEmpty(ostream& out);
void testToStringNonEmpty(ostream& out);
int main() {
testSizeEmpty(std::cout);
} testToStringNonEmpty(std::cout);
void testSizeEmpty(ostream& out) {
out << “DNA empty size: “;
DNA_Strand dna1;
if (dna1.size() == (size_t)0) {
out << PASS << endl;
} else {
} } out << “Expected 0. Received: ” << dna1.size() << endl;
void testToStringNonEmpty(ostream& out) {
out << “toString nonEmpty: “;
std::string ipStr = “ABCCTG”;
DNA_Strand dna(ipStr);
//toString should return the contents as a string
if(dna.toString()==ipStr) {
} out << PASS << endl;
else {
} } out << “Expected: ” << ipStr << ” Received: ” << dna.toString() << endl;
As you can see, this gives us a lot more flexibility when outputting error messages. Testing Exceptions:
We should make it our goal to test all of the behavior described by the contract (as defined in the technical specification or the header file). Good documentation describes what happens on good input as well as on bad. We should be testing this “bad” behavior as well.
As an example, let’s consider the get(char, size_t) method from our DNA_Strand class.
// Get an item in the DNA_Strand at location index. Throws
// if index is out of range, i.e., larger than the // current size of the DNA_Strand.

// Uses zero-based indexing.
char get (size_t index);
We should test that get() behaves correctly when presented with an invalid index. Here is a sample test for this case:
void testGet_nonempty_fail(ostream& out) {
out << “get() nonempty fail: “;
std::string ipStr = “ABCCTG”;
DNA_Strand dna(ipStr);
try {
char ch = dna.get(19); // This statement will throw an exception
} out << ” get() should have thrown an exception.” << endl;
catch (std::out_of_range&) {
} out << PASS << endl;
catch (…) {
} } out << ” get() threw the wrong exception.” << endl;
It might be a bit counter-intuitive at first, but in order for this test to pass successfully we need the right exception to be thrown. That’s why the only PASS output is produced inside the catch clause for std::out_of_range. If for some reason the call to get() does not fail an error message is generated and the test fails. The last alternative is that the call did throw an exception but it wasn’t the right type of an exception. In that case the catch all clause, catch (…), kicks in and we display another error message.