PA1: Teethbrushes
Categories:
13 minute read
Programming Assignment 1

🛑 To Know Before You Start
Since this is a programming assignment (not a homework assignment) it is longer and will take more time than any of the assignments you have completed so far.Learning Objectives
This programming assignment is designed to help you learn several things. First, it will help you learn about specialization (i.e., derived classes), inheritance, and overriden methods. Second, it will help you learn about reading from and writing to the file system (i.e., file input and output). Finally, it will help you become familiar with packages.
Overview
You may have heard, or you may have observed first-hand, that computer science students sometimes have personal hygiene problems. (Not you of course, but perhaps some of your fellow students?) A recent survey identified part of the problem. Many computer science students only brush one tooth (rather than all of them) because they were told to use a toothbrush and the word tooth is singular. An enterprising company has decided to take advantage of this confusion by selling teethbrushes instead.
At the moment, they are starting to build relationships. For example, they have contracted with “Dr. Teeth and the Electric Mayhem” to write their advertising jingles, and they have contracted with you to implement some of the classes needed for their inventory system.
Background
A physical Teethbrush
consists of a head (and associated handle
or stem) while a physical ElectricTeethbrush
consists of a head
and a body. The bristles in the head can be flat or polished
(i.e., rounded). The body of an ElectricTeethbrush
can be
rechargeable or not, and can provide ultrasonic cleaning (via the
head) or not.
The cost of a Teethbrush
is the sum of the BASE_HEAD_COST
($2.00),
the hardness cost, and the POLISHED_UPCHARGE
($0.75) if the bristles
are polished. The hardness cost is the product of the hardness
(which is in the closed interval [0, 5]) of the bristles and the
HARDNESS_UPCHARGE
($0.10). So, the harder the bristles, the higher the
cost. For example, a Teethbrush
that has polished bristles with a
hardness of 5 costs $2.00 + $0.75 + $0.50 = $3.25
The head of an ElectricTeethbrush
costs the same as the head of a
Teethbrush
. However, an ElectricTeethbrush
comes with multiple
heads, whereas a Teethbrush
has only one. Hence, the cost of an
ElectricTeethbrush
is the product of the NUMBER_OF_HEADS
(5) and
the cost of a Teethbrush
, plus the BASE_BODY_COST
($5.00), plus
the RECHARGEABLE_UPCHARGE
($20.00) and the ULTRASONIC_UPCHARGE
($10.00) as appropriate. For example, a basic ElectricTeethbrush
that has polished bristles with a hardness of 0 has an initial cost of
$13.75 + $5.00 = $18.75, and a rechargeable version would cost $18.75 +
$20.00 = $38.75.
The shipping cost of an order is the product of the unit shipping
cost and the order size, plus a STOCKING_COST
($25.00) if the size of
the order is greater than the current inventory level. The unit
shipping cost is either the UNIT_SHIPPING_COST_OVERSEAS
($0.30) or
the UNIT_SHIPPING_COST_LOCAL
($0.10), reduced by the
LARGE_ORDER_DISCOUNT
(30.0%) if the order is greater than
LARGE_ORDER
(1000). For example, suppose someone wants to ship an
order of 2000 Teethbrush
overseas when there are 100 in
inventory. The unit shipping cost will be $0.21 (the $0.30 minus the
large order discount of $0.09), meaning the total shipping cost will be $445.00
(i.e., $0.21 x 2000 = $420.00 plus the $25.00 stocking cost).
The Classes to be Written
You must write the Teethbrush
, ElectricTeethbrush
, and
ProductFileProcessor
classes that are summarized in the following
UML class diagram.

Note that attributes and methods that are inherited are not made explicit in this diagram. If a method appears in both a base class and a derived class it means that the method in the derived class overrides the method in the base class.
The Teethbrush
Class
As discussed above and as shown in the UML class diagram,
a Teethbrush
object is characterized by the hardness of the
bristles (on a scale of 0-5), and whether the bristles are polished or
not (i.e., whether the part of the bristle that comes in contacts with
the teeth is flat or rounded). A Teethbrush
object also has an
associated inventory level.
In addition to the specifications contained in the UML class diagram and the background discussion above, this class must conform to the following specifications.
- Any time someone attempts to set the
hardness
attribute to a value less than 0 it must be set to 0. - Any time someone attempts
to set the
hardness
attribute to a value greater than 5 it must be set to 5. - The
changeInventory()
method can be used to increase (with a positive parameter) or decrease (with a negative parameter) theinventory
attribute. It must not change theinventory
attribute (and must returnfalse
) if the change would make theinventory
attribute negative. Otherwise, it must make the change and returntrue
.
The ElectricTeethbrush
Class
As discussed above and as shown in the UML class diagram, in addition
to the attributes of a Teethbrush
, an ElectricTeethbrush
can be
rechargeable or not, and can be ultrasonic or not.
In addition to the specifications contained in the UML class diagram and background discussion above, this class must conform to the following specifications.
- The
cost()
method in theElectricTeethbrush
class must not duplicate any code in the method that it overrides.
The ProductFileProcessor
Class
The ProductFileProcessor
is a utility class that can be used to
read/write Teethbrush
and ElectricTeethbrush
information from/to
the file system in (a simplified) comma-separated-valued (CSV) format
in which fields are delimited by a comma and there is a newline
character at the end of a record. For example, the CSV file for
an electric toothbrush might be as follows:
0,3,true,false,true
In addition to the specifications contained in the UML class diagram, this class must conform to the following specifications.
- The file name to use when reading and writing must be the model
name followed by
".bru"
. So, for example, the information about model"E1003"
must be in a file named"E1003.bru"
(in the working directory/folder). - All objects used for reading and writing must be closed when they are no longer needed.
- The
writeTeethbrush()
method must write theinventory
,hardness
, andpolished
attributes using"%d,%d,%b\n"
as the formatString
- The
writeElectricTeethbrush()
method must write theinventory
,hardness
,polished
,rechargeable
andultrasonic
attributes using"%d,%d,%b,%b,%b\n"
as the formatString
- The
readTeethbrush()
method must read a file written by thewriteTeethBrush()
method, construct and initialize aTeethbrush
object, and return it. - The
readElectricTeethbrush()
method must read a file written by thewriteElectricTeethBrush()
method, construct and initialize anElectricTeethbrush
object, and return it.
Unit Testing
You must write JUnit tests for the Teethbrush
, ElectricTeethbrush
, and
ProductFileProcessor
classes. Your JUnit test suite must cover all
statements and all branches (as measured by EclEmma) in all of the
classes you write. Your tests must be in a package named testing and
each test class must include the word “Test” in its name.
Submission
You must submit (using Gradescope) a .zip
file named pa1.zip
that contains:
Your implementation of the
Teethbrush
,ElectricTeethbrush
, andProductFileProcessor
classes.Your JUnit tests.
packaged appropriately.
Do not submit any .bru
files. To test the read methods in your
ProductFileProcessor
class you must create a JUnit test that first executes
the appropriate write method and then executes the appropriate read method.
(This is sometimes called “round trip” testing of input/output.) Note that,
to ensure that the write happens before the read, the two must be in the same
JUnit test. You can (and should) have multiple tests of this kind, but each
must be independent of the others.
There is no limit on the number of submissions and no penalty for excessive submissions. Note that your submission will not be graded if it does not comply with the specifications. So, if you do not complete a class your submission should include a stubbed-out version of it. This will allow you to potentially get credit for the classes/methods that you do complete.
Grading
Your code will first be graded by Gradescope and then by the Professor. The grade you receive from Gradescope is the maximum grade that you can receive on the assignment
Gradescope Grading
Your code must compile (in Gradescope, this will be indicated in the section on “Does your code compile?”) and all class names and method signatures must comply with the specifications (in Gradescope, this will be indicated in the section on “Do your class names, method signatures, etc. comply with the specifications?”) for you to receive any points on this assignment. Gradescope will then grade your submission as follows:
Criterion | Points | Details |
---|---|---|
Conformance to the Style Guide | 0 | Success Required |
Passing Your Tests | 10 | All or Nothing; Success Required |
Coverage of Your Tests | 20 | Partial Credit Possible |
Correctness | 70 | Partial Credit Possible |
Note that some of the criteria are described as “Success Required”. This means that Gradescope will not assess subsequent criteria unless this criterion is satisfied (and you will receive a grade of 0 for the criteria that aren’t assessed). So, for this assignment, if your code does not conform to the style guide then nothing else will be assessed (and you will receive a grade of 0 for the assignment). Similarly, if your code does not pass your tests, nothing else will be assessed and you will receive a grade of at most 10.
Gradescope will provide you with hints, but may not completely identify the defects in your submission.
Manual Grading
After the due date, the Professor may manually review your code. At this time, points may be deducted for inelegant code, inappropriate variable names, bad comments, etc.
Recommended Process
Since nobody will be looking over your shoulder, you can use any process that you would like to use. However, it is strongly recommended that you use the process described here.
Get Started
Read and understand the entire assignment.
In Eclipse, create a project for this assignment named
pa1
. (Remember, do not create a module, and create separate folders for source and class files).In Eclipse, create three packages (in the project) named
product
,product.io
, andtesting
. Do not have Eclipse createpackage-info.java
for any of these packages.Activate Checkstyle for this assignment.
Create Test Cases for Teethbrush
and ElectricTeethbrush
By hand (i.e., using pencil and paper), create several black-box tests cases (i.e., inputs and expected outputs) for the
cost()
method in theTeethbrush
class. Some of these tests should involve random inputs and some should involve rules-of-thumb.By hand, create tests several black-box cases for the
shippingCost()
method in theTeethbrush
class. Some of these tests should involve random inputs and some should involve rules-of-thumb.By hand, create sevearl black-box tests cases for the
cost()
method in theElectricTeethbrush
class. Some of these tests should involve random inputs and some should involve rules-of-thumb.
Writing these black-box test cases before you start writing the code is called test driven development (TDD). Using TDD will help you understand the algorithms that you need to write.
Stub-Out the Classes
- Stub-out the
Teethbrush
class. - Stub-out the
ElectricTeethbrush
class. - Stub-out the
ProductFileProcessor
class. - Add the “javadoc” comments to the three classes class.
- Check the style of the three classes and make any necessary corrections.
Implement and Test the Classes
Implement the constructor, setters, and simple getters in the
Teethbrush
class.Test the constructor, setters, and simple getters in the
Teethbrush
class using the black-box tests (and debug if necessary).If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).
Implement the constructor and simple getters in the
ElectricTeethbrush
class.Test the constructor and simple getters in the
ElectricTeethbrush
class using the black-box tests (and debug if necessary).If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).
Implement the
shippingCost()
method in theTeethbrush
class.Test the
shippingCost()
method in theTeethbrush
class using the black-box tests (and debug if necessary).If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).
Implement the
cost()
method in theTeethbrush
class.Test the
cost()
method in theTeethbrush
class using the black-box tests (and debug if necessary).If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).
Implement the
cost()
method in theElectricTeethbrush
class.Test the
cost()
method in theElectricTeethbrush
class using the black-box tests (and debug if necessary).If necessary, add white-box tests to get 100% statement coverage and 100% branch coverage (and debug if necessary).
Use the same kind of process to develop, test, and debug the
ProductFileProcessor
class.
Help
Help is available on the following topics.
Help Creating Packages
Help with creating packages in Eclipse is available on the Department’s Wiki at:
Help Creating Files (Including Files in a Package)
Help with creating files in Eclipse (including files in a package) is available on the Department’s Wiki at:
Help with JUnit
You should be fairly proficient with JUnit at this point (especially since we will be using JUnit for the rest of the semester). However, if you are still having trouble, help is available at:
Help with Coverage
In order to get 100% coverage, you sometimes have to be aware of some quirks of the language you are working in, and the tool set you are using. For more information, see:
Help Creating the .zip
File
The directories/folders containing the packages must appear at the top
of the .zip
file. So, you must not compress the directory/folder
containing these directories/folders, you must compress the
directories/folders containing the packages. In other words, if you
have a directory named src
that contains the directories product
and testing
, you must not compress src
, you must compress
product
and testing
. (Note that the io
directory/folder will be
inside of the product
directory/folder.)
Help with creating .zip
files is available on the CS Wiki. In
particular, see:
Note that your .zip
file must only contain .java
files, not
.class
files. This will be much easier to accomplish if, when you
create your project, you instruct Eclipse to use separate
directories/folders for source and class files.
Help Using a Scanner
There are two delimiters used in CSV files, the comma that separates fields
and the newline character that separates records (or lines). To instruct
a Scanner
to use a particular delimiter or delimiters you must invoke its useDelimiter()
method. To instruct it to use just commas as delimiters you must pass it ","
,
to instruct it to use just newlines as delimiters you must pass it "\n"
, and
to instruct it to use both you must pass it "[,\n]"
(which is a regular expression
that matches both).
Help Using a BufferedReader
There are two delimiters used in CSV files, the comma that separates fields
and the newline character that separates records (or lines). If you choose
to use a BufferedReader
you will read an entire record (including the newline
character) using the readLine()
method. You can then tokenize it either using the
split()
method in the String
class (passing it ","
as the delimiter) or using
a StringTokenizer
object (again using ","
as the delimiter).
Questions to Think About
You don’t have to submit your answers to these questions, but you should try to answer them because they will help you determine whether or not you understand some of the important concepts covered in this assignment.
Would the design of the
Teethbrush
class be improved by using a 0-1 indicator for thepolished
attribute (as discussed in Chapter 6 of Patterns for Beginning Programmers ) rather than using aboolean
value? What would change in the constructor,cost()
method, andisPolished()
method?What is gained by using specialization in this assignment? In other words, what is gained from having the
ElectricTeethbrush
class extend theTeethbrush
class?Is there code duplication in the “read” methods of the
ProductFileProcessor
class? Why is this troubling?Is there code duplication in the “write” methods of the
ProductFileProcessor
class? Why is this troubling?Given the number of classes in this assignment, are the packages that helpful? When is the use of packages likely to be more helpful?