Exercise 3

Due: before noon on Friday 1 February 2013

Pre-marking: first run at noon on Wed. 30 Jan.; second run at noon on Thu. 31 Jan.

There are two parts to this exercise. For each part, there is a single file you must submit — make sure that you read the submission instructions carefully!

This exercise is longer than the first two, but don't panic! A lot of the code is "repeated", as you will see. Just take it one step at a time...

Important general advice

BEFORE you begin coding, make sure that you understand everything in this handout. Remember that the point of these exercises is not to get a "working" program by any means necessary — it is to ensure that you understand how to write the desired code. If you succeed in writing something that works but you do not understand why, then you have failed, no matter what grade you receive!

In particular, if there is something you do not quite understand, please, for your own sake, take the time to read the online textbook and the course notes and readings, do some searching on Google and ask on the course forum or during office hours to make sure you find out. Keep in mind that the lab for this week will cover related material, so taking the time to understand the lab (and ask questions of other students and of your TA) should provide good preparation for this exercise!

Part A

Remember that in Python, a class is allowed to have more than one parent class. For example, to make class `C` be a sub-class of both `A` and `B`, you would define class `C` as follows:

```    ...code for classes A and B is up here...

class C(A, B):
...code for class C goes here...
```

Submit a file "`e3a.py`" that defines the following classes to represent various geometrical shapes. Think carefully about the relationships between the different classes: some of these really should be sub-classes of each other.

• `Parallelogram`: a four sided figure with parallel pairs of sides. A Parallelogram is defined by the lengths of its two pairs of sides (labelled base and side in the picture below) and the interior angle (in degrees) between adjacent sides (labelled theta in the picture below).

Your class must implement methods to provide the following functionality.

• `Parallelogram` objects are created by specifying the lengths of their `base` and `side`, as well as the angle `theta` between them (in degrees) — write your constructor appropriately!
• When a `Parallelogram` object is `print`ed (thereby calling its `__str__` method), the output has the following form (where `base`, `side`, and `theta` are replaced by the appropriate floating-point values, of course):
```    a Parallelogram with side lengths base and side, and interior angle theta
```
Pay attention to get this exactly right, including all the punctuation and capitalization!
• `Rectangle`: a parallelogram with four right angles. A Rectangle is defined by the lengths of its two pairs of sides (labelled base and side in the picture below).

Your class must implement methods to provide the following functionality.

• `Rectangle` objects are created by specifying the lengths of their `base` and `side` — write your constructor appropriately!
• When a `Rectangle` object is `print`ed (thereby calling its `__str__` method), the output has the following form (where `base` and `side` are replaced by the appropriate floating-point values, of course):
```    a Rectangle with side lengths base and side
```
Pay attention to get this exactly right, including all the punctuation and capitalization!
• `Rhombus`: a parallelogram with four equal sides. A Rhombus is defined by the length of its sides (labelled base in the picture below) and the interior angle (in degrees) between adjacent sides (labelled theta in the picture below).

Your class must implement methods to provide the following functionality.

• `Rhombus` objects are created by specifying the length of their `base` and the angle `theta` between adjacent sides (in degrees) — write your constructor appropriately!
• When a `Rhombus` object is `print`ed (thereby calling its `__str__` method), the output has the following form (where `base` and `theta` are replaced by the appropriate floating-point values, of course):
```    a Rhombus with side length base and interior angle theta
```
Pay attention to get this exactly right, including all the punctuation and capitalization!
• `Square`: a parallelogram with four equal sides and four right angles; both a Rectangle and a Rhombus. A Square is defined by the length of its sides (labelled base in the picture below).

Your class must implement methods to provide the following functionality.

• `Square` objects are created by specifying the length of their `base` — write your constructor appropriately!
• When a `Square` object is `print`ed (thereby calling its `__str__` method), the output has the following form (where `base` is replaced by the appropriate floating-point value, of course):
```    a Square with side length base
```
Pay attention to get this exactly right, including all the punctuation and capitalization!
• In addition, if `s` is an object from any one of these classes, then the call `s.area()` must `return` the area of `s`. Note that the formula to compute the area of a parallelogram is: base × side × sin(theta).
Warning: function `math.sin` in Python expects its argument to be an angle given in radians — take a look at the function `math.radians` to convert between degrees and radians.

• Throughout, make appropriate use of inheritance to reduce code duplication: wherever possible, reuse methods from parent classes — in particular, don't forget to call constructors from parent classes when appropriate.

Part B

Submit a file `e3b.py` that contains a suite of unit tests for the classes you wrote in Part A. Your file must contain the following subclassses of `unittest.TestCase` (one for each one of the classes in Part A):

• `TestParallelogram`
• `TestRectangle`
• `TestRhombus`
• `TestSquare`

Each of the test classes above must contain at least the following methods (the strange names were chosen to ensure that the test cases are run in a particular order):

• `test_0_init`: test that objects can be created correctly for the class.
• `test_1_str`: test that objects of the class are converted to strings as specified.
• `test_2_area`: test that the area of objects is computed correctly.

Don't forget to put the statement `unittest.main()` under the ` if __name__ == '__main__': ` block at the bottom of your file, to execute the test cases. Now, you can run your test cases yourself to verify your Part A. (But don't worry: we will also run our own suite of test cases on your `e3a.py`!)