Testing and Debugging solution
Testing and debugging are important steps in programming. Loosely, you can think of testing as verifying that your program works and debugging as ﬁnding and ﬁxing errors once you’ve discovered it does not. Writing test code is an important (and sometimes tedious) step. Many software libraries have “regression tests” that run automatically to verify that code is behaving the way it should.Here are four strategies for testing and debugging: 1. When you write a class, write a separate “driver” main function that calls each member function, providing input that produces a known, correct result. Output of the actual result or, better yet, automatic comparison between actual and correct result allows for verifying the correctness of a class and its member functions. 2. Carefully reading the code. In doing so, you must strive to read what the code actually says and does rather than what you think and hope it will do. Although developing this skill isn’t necessarily easy, it is important. 3. Using the debugger to (a) step through your program, (b) check the contents of various variables, and (c) locate ﬂoating point exceptions and segmentation violations that cause your program to crash. 4. Judicious use of std::cout statements to see what the program is actually doing. This is useful for printing the contents of a large data structure or class, especially when it is hard to visualize large objects using the debugger alone. Points and Rectangles The programming context for this lab is the problem of determining what 2D points are in what 2D rectangles. For rectangles, we will assume they are aligned with the coordinate axes, as shown in the ﬁgure below. This makes it easy to represent and to test if a point is inside. Our code will store points in rectangles and determine which points are in which rectangles. This is a toy example of problems that must be addressed in graphics and robotics. (4,3) (17,9) (9,3.5) (8,10) x y Figure 1: Example of a rectangle aligned with the coordinate axes — the only type of rectangle considered here. The rectangle is speciﬁed by its upper right corner point, (17,9), and its lower left corner point, (4,3). The point (9,3.5) is inside the rectangle, whereas the point (8,10) is outside. Please download the following 3 ﬁles needed for this lab: http://www.cs.rpi.edu/academics/courses/spring15/csci1200/labs/04_debugging/Point2D.h http://www.cs.rpi.edu/academics/courses/spring15/csci1200/labs/04_debugging/Rectangle.h http://www.cs.rpi.edu/academics/courses/spring15/csci1200/labs/04_debugging/Rectangle.cpp Checkpoint 1 Examine the provided ﬁles brieﬂy. Point2D.h deﬁnes a simple, self-contained class for representing point coordinates in two-dimensions. No associated .cpp ﬁle is needed because all member functions are deﬁned in the class declaration. Rectangle.h and Rectangle.cpp contain the start of the Rectangle class. We have placed an intentional bug in the Rectangle class! Please read the code now to see if you can ﬁnd it. Do not worry if you can not. If you do ﬁnd the bug, do not ﬁx it! First, complete the implementation of the Rectangle.cpp class. Look through Rectangle.h and Rectangle.cpp to determine what functions need to be added. Then, compile these ﬁles and remove any compilation errors (but do not ﬁx runtime logic bugs in the provided code). Next, create a new ﬁle named test rectangle.cpp. Create a main function within this ﬁle. In the main function, write code to test each of the member functions. For example, write code to create several rectangles, and print their contents right after they are created. Write code that should produce both true and false in the function is point within. In fact, if there is non-trivial logic in any function, the test code should call the function several (or even many) times with varying inputs to test all the possible branches or paths through the conditionals and loops to ensure every line of code is run at least once. Write code to add points (or not) to a rectangle. Write code to ﬁnd what points are contained within the bounds of both rectangles. To complete this checkpoint, show a TA your test cases and the error(s) that those test cases reveal. After doing this you should be able to spot that there is an error in the provided code (as well as, perhaps, errors in your own code). Even if you know where the bug or bugs occur, please do not ﬁx them yet. Checkpoint 2 Now, we will practice using the debugger to ﬁnd and ﬁx errors. Today we’ll learn how to use the gcc/g++ command line debugger, gdb from the GNU/Linux, MacOSX, or Cygwin terminal. NOTE: On Mac OSX, you are probably actually using the llvm/clang++ compiler, so you’ll use lldb instead of gdb in the instructions below. If you’re using Windows and you didn’t already install gdb for Cygwin, you’ll need to upgrade Cygwin to grab that package. Many introductory gdb debugging tutorials can be found on-line; just type gdb tutorial into your favorite search engine. Here are a couple: http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html http://www.cs.cmu.edu/~gilpin/tutorial/ After you learn and demonstrate to your TA the basics of debugging with gdb/lldb you are encouraged to explore other debuggers, for example, the debugger built into your IDE, but we do not provide those instructions. You may also want to try a graphical front end for gdb: http://www.gnu.org/software/ddd/ After today’s lab you can use your favorite search engine to ﬁnd basic instructions for other debuggers and ﬁgure out how to do each of the steps below in your debugger of choice. Note that in addition to a standard step-by-step program debugger like gdb/lldb, we also recommend the use of a memory debugger for programs with dynamically-allocated memory, or anytime you have a segmentation fault or other confusing program behavior. Information about memory debuggers is available here: http://www.cs.rpi.edu/academics/courses/spring15/csci1200/memory_debugging.php After today’s lab, you should be comfortable with the basics of debugging within your preferred development environment. Keep practicing with the debugger on your future homeworks, and be prepared to demonstrate debugger skills when you ask for help in oﬃce hours. 1. Run your program that has tests for the basic member functions. Even though the program will compile and run, it will not give the correct output. You may be suspicious about a place in your code where the error occurs. It is time to start the debugger. 2. Getting started: When you plan to use the gdb (or lldb) debugger to investigate your program you will need to build your executable diﬀerently. Speciﬁcally you need to link the code with the -g option to add debug information (including, source code line numbers!) to the executable. For example, to compile & link all of your ﬁles for this lab type: g++ -Wall -g Rectangle.cpp rectangle_test.cpp -o rect_test In order to start gdb type gdb rect_test This puts you into the command-line debugger. Type help in order to see the list of commands. 2 There are several commands for setting breakpoints. You can set a breakpoint by specifying a function name or a line number within a ﬁle. For example break main sets a breakpoint at the start of the main function. You can also set a breakpoint at the start of a member function, as in break Rectangle::add_point Finally, to set a breakpoint at a speciﬁc line number in a ﬁle, you may type: break foo.cpp:65 Set a breakpoint at some point in your code just before (in order of execution!) you think the ﬁrst error might occur. Finally, in order to actually start running the program under control of the debugger, you will need to type run at the gdb command line. 3. Stepping through the program: You can step through the code using the commands next (move to the next line of code), step (enter the function), and finish (leave the function). The command continue allows you to move to the next breakpoint. 4. Examining the content of variables: You can use print to see the values of variables and expressions. You can use the command display to see the contents of a particular variable or expression when the program is stopped. 5. Program ﬂow: The command backtrace can be used to show the contents of the call stack. This is particularly important if your program crashes. Unfortunately, the crash often occurs inside C++ library code. Therefore, when you look at the call stack the ﬁrst few functions listed may not be your code. Find the function on the stack that is the nearest to the top of the stack that is actually your code. By typing frame N, where N is the index of the function on the stack, you can examine your code and variables and you can see the line number in your code that caused the crash. Type info locals and info args to examine the data in the function. Type list to see the source code. 6. Breakpoint on Variable Change: The last powerful debugger feature you will ﬁnd out about today is variable monitoring. Create an instance of a Point2D object called pt in your main function and change its coordinates using the set member function of Point2D. You will now monitor the change of this point using the debugger. You can use the command watch to halt the program when a variable or expression changes. For example, type watch p.m_x. You can try the the rwatch command which allows you to break on a read of the value (not just a change). Continue to experiment with these diﬀerent debugger operations and only when you feel comfortable showing oﬀ all these features put your name in the queue for checkoﬀ for this checkpoint. The TA/mentor will be asking you to demonstrate these features, especially how you can make the debugger pause when a variable is changed. You will also be asked questions about the other steps in debugging. Checkpoint 3 For the remainder of the lab time, please work on Homework 3, and ask your TA/mentors lots of questions! If you haven’t already done so, install a memory debugger on your laptop and try it out on your homework code, even if you’re not stuck on a segmentation fault or other suspicious situation of memory corruption. Read the memory debugger output carefully and ask a TA/mentor for help interpreting these messages. (∼10 minutes before the end of lab:) To complete this checkpoint and the entire lab, show a TA your progress on the homework and sample memory debugger output on your laptop.
You'll get 1 file (214.0KB)