Homework 11: Testing

Due: 8:00 a.m., Friday, 12 October 2007
No extensions!

Summary: In this assignment, you will have the opportunity to develop test suites for two interesting procedures.  You will also develop versions of those procedures.

Purposes:  To give you experience in thinking about and writing test suites.  To introduce you to two important procedures, one useful primarily for image processing, the other more generally useful.

Expected Time: 1-3 hours.

Collaboration: I encourage you to work in groups of size three. You may, however, work alone or work in a group of size two or size four. You may discuss this assignment with anyone, provided you credit such discussions when you submit the assignment.

Submitting: Email me your answer. More details below.

Warning: So that this assignment is a learning experience for everyone, I may spend class time publicly critiquing your work.

Contents:


Assignment

Problem 1: Weighted Color Averages

In this problem, you'll complete and extend Exercise 5 from the lab on verifying preconditions.

In a number of exercises, we were required to blend two colors. For example, we blended colors in a variety of ways to make interesting images, and we made a color more grey by averaging it with grey. In blending two colors, we are, in essence, creating an average of the two colors, but an average in which each color contributes a different percent.

For this problem, we might write a procedure, (rgb.weighted-average fraction color1 color2) that makes a new color, each of whose components is computed by multiplying the corresponding component of color1 by fraction and adding that to the result of multiplying the corresponding component of color2 by (1-fraction). For example, we might compute the red component with

(+ (* fraction (rgb.red color1)) (* (- 1 fraction) (rgb.red color2)))

a. What preconditions should rgb.weighted-average have? (Think about restrictions on fraction, color1, and color2.)

b. How might you formally specify the postconditions for rgb.weighted-average?

c. Document rgb.weighted-average.

d. Because we so frequently find weighted averages of colors, it's really important that our weighted average code work correctly. Write a test suite for rgb.weighted-average, as in the lab on testing. (By writing the tests before you write the code, you are practicing test-driven development!)

e. Write the code for rgb.weighted-average, making sure to verify each precondition.

Problem 2: Removing Duplicates

We might wish to remove duplicates from a list of items: e.g., from a list of color names or from a list of spots. For example,
> (remove-duplicates (list "red" "green" "blue" "yellow" "red" "orange"))
(
"green" "blue" "yellow" "red" "orange")

a. Document remove-duplicates.

b. Write a test suite for remove-duplicates. Because we didn't say which duplicate to remove, you may wish to use the test-permutation! procedure described below.

c. Implement remove-duplicates, making sure to verify each precondition. You may find the member? procedure we wrote for Homework 9 (and later documented) to be helpful.


Important Evaluation Criteria

I will look primarily at the precision of your documentation, the thoroughness of your tests, and whether each procedure is implemented correctly. 

Students whose test suites catch errors in other students' code  or whose code passes all of the class's tests may receive a higher grade.

Submitting Your Homework

Please submit this work via email. The email should be titled CSC151 HW11 and should contain your answers to all parts of this assignment.

Please send your procedure definitions as the body of an email message.


Appendix: Testing list operations with test-permutation!

The unit testing framework includes another keyword we haven't used yet: test-permutation! This lets you make sure an expression yields a list containing the correct items, but it doesn't care what order the items are in.

Here is a sample test suite using test-permutation!:

(load "/home/davisjan/csc/151/examples/unit-test.ss")
(begin-tests!)
(define one-to-five (list 1 2 3 4 5))
(test-permutation! (list 1 2 3 4 5) one-to-five)
(test-permutation! (list 1 3 5 2 4) one-to-five)
(test-permutation! (reverse one-to-five) one-to-five)
(test-permutation! (cdr one-to-five) one-to-five) ; Should fail: missing an element
(test-permutation! null one-to-five) ; Should fail: missing all elements
(test-permutation! (list 6 5 1 4 2 3) one-to-five) ; Should fail: extra element
(end-tests!)

The first three tests should succeed, because the expression to be tested gives a list that contains the elements 1, 2, 3, 4, and 5, even though they are not necessarily in that order. The rest of the tests should fail. (Of course, you shouldn't write tests that you expect to fail; I'm just trying to show you how test-procedure! works.)

What actually happens?  Let's see:

6 tests conducted.
3 tests failed.
No errors encountered.
3 other tests failed to give the expected result:
For (cdr one-to-five) expected [(permutation-of (1 2 3 4 5))] got [(2 3 4 5)]
For null expected [(permutation-of (1 2 3 4 5))] got [()]
For (list 6 5 1 4 2 3) expected [(permutation-of (1 2 3 4 5))] got [(6 5 1 4 2 3)]
Sorry. You'll need to fix your code.
>

Yes, that is what I expected to happen.


Janet Davis (davisjan@cs.grinnell.edu)

Created October 8, 2007
Last revised October 9, 2007