COMP122 2020 Assignment 3
This assignment is due on 30/03/2020 at 5pm and should be submitted via SAM Electronic Submissions server (see the end of this page for detailed instructions).
Requirements
You will write a program that reads a list of items and their prices from a text file and creates a vending machine that sells these items.
Part 1. Reading Items from a text file
Write a method that reads a list of items (with price and description) from a given text file
and handles all possible exceptions that may occur.
To store the data, each item should be represented as an instance of the given class Item.
This class has private attributes price (a double) and description (a String), together with
“getter” methods, as usual.
You can instantiate an item object using its two-parameter constructor method,
which simply stores the given values in its attributes.
public Item(double price, String description) { … }
Write a class called Vendor that includes a static method called itemsFromFile.
This should open the text file, read its input and create (and return)
an array of Items specified in that file.
To be precise, the method must have the following signature.
public static Item[] itemsFromFile(String fileName);
You can assume that every line of text in the given file contains
a string of the form XXX.YYY;DDDD where XXX.YYY is the price of the item (in decimal notation, not necessarily with only 3 digits after the point), followed by the description DDDD of the item (again, not necessarily of length 4),
separated by a semi-colon (;).
For example, a text file with content
1.0;Cookies
0.5;Milk
3.1415;Crystal Meth
should be read into a length-3 array where the first element is an Item with price 1.01.01.0 and description “Cookies”
(as the values of its private attributes), the second is an Item with price 0.50.50.5 and description “Milk”, and so on.
Your method should handle all possible exceptions, including “file not found”, or if a line of text cannot be interpreted correctly.
It must not throw any exceptions itself.
If a line cannot be interpreted (or a file cannot be read) you may print an error message on System.err,
but should otherwise simply continue reading the input from the next line.
For example, if you change the first line in the text file above into
ABC1.0;Cokies
your method will fail to read this line but should still return an array of length 2 containing the remaining items.
You will find a few demo text files under src/items.*.txt.
Hint: You can use the Scanner class (java.util.Scanner) to extract strings line by line from a larger string, and also to parse the next number
(see lecture 6a).
Hint: Although you should ultimately return an array of Items,
it may be more convenient to internally use a List (for instance an ArrayList<Item>) to store the read items,
because you don’t know the length of the final array before reading the file completely.
Hint: The exercise does not ask for a main method so we will not be looking for (or executing) that.
You may of course add such a method in order to test your class.
Part 2. A parametrised vending machine
Write a class called VendingMachine, which can sell a given list of items.
Your class must have a constructor method that takes exactly one parameter, namely an array of Items:
public VendingMachine(Item[] items) { … }
These items should be stored in the vending machine somehow to be accessed later.
You should also keep track of which items have been sold already.
The class should have a private double attribute cassette and a corresponding getter public double getCassette().
Moreover, there must be public methods as follows.
a method called “insertCoin”
public void insertCoin(double coin)
that adds the value of is parameter to the cassette.
This method should throw an java.lang.IllegalArgumentException if the given coin is not of the right denomination.
Acceptable values are 0.01,0.02,0.05,0.1,0.2,0.5,1, and 2.
a method called “returnCoins”
public double returnCoins()
that empties the cassette and returns its value.
a method called “display”
public String display()
that returns the value of the cassette as a string in the form $X.YY,
meaning a dollar symbol followed by its value in decimal notation with exactly two digits after the point.
Hint: check out lab 4, exercise 1.5 for the string formatting.
a method called “getItem”
public Item getItem(int i)
that sells the ithi^{th}ith item.
It should check if the price of the item is at most the value of cassette.
If so it returns the item, updates the cassette and remembers that the item was sold.
If the parameter i is not a valid array index (is greater equal the number of stored items) this should throw an IllegalArgumentException.
There are two other possible error situations, which should be dealt with by throwing specialized RuntimeExceptions:
If the price of the item exceeds the value of the cassette you should throw CassetteException.
If the item at the given position has already been sold you should throw ItemSoldException.
These two types of exceptions are of course not part of the Java standard library,
so you will need to define them yourself (Hint: see lecture 7a
and lab 8).
Part 3. Unit tests
Write JUnit4 unit tests for the vending machine of part 2.
In each test case, you should create a new VendingMachine object using an appropriate array of Items for your test,
and interact with it in a way that checks the tested behaviour.
Notice that the aim here is to write unit tests that test for the specific behaviour stated here.
Don’t bend the tests so that they all pass for your solution to part 2 as they will be checked independently.
Write a class called TestVendingMachine that contains unit tests (methods) as follows.
testInsertCoinIncrease should check that calling insertCoin with a parameter 1.0 on a VendingMachine instance correctly increments its cassette by one (as observed by calling its getter).
testInsertCoinDecrease should check that calling insertCoin with a parameter -1.0 decrements the cassette by one (as observed by calling its getter). Yes, this is not the behaviour specified in part 2, so a correct implementation for part 2 should fail this test.
testInsertCoinValidDenomination should check that calling insertCoin with a parameter that is not one of the expected ones (0.01,0.02,0.05,0.1,0.2,0.5,1, and 2) throws an IllegalArgumentException.
testDisplay should check that the string returned by the display method is in the format described in part 2.
This test should fail if the result contains extra spaces, or has too many digits.
testReturnCoinsGetsAll should check that calling returnCoins returns the value of the cassette (just before calling returnCoins).
testReturnCoinsEmptiesCassette should check that calling returnCoins results in the cassette being reset to zero.
testGetItemSale should check that getItem returns the correct item, assuming that the cassette is sufficient.
testGetItemTwiceSold should check that the getItem method throws a ItemSoldException
when it is called for the second time with the same parameter (assuming that the cassette is sufficient).
testGetItemTooExpensive should check that the getItem method throws a CassetteException
if the requested item costs more than the value of the cassette.
testGetItemDoesNotExist should check that the getItem method throws an IllegalArgumentException if the parameter i (the item index) is not a valid array index (is greater equal the number of stored items).
Marking Scheme
Part
1
2
3
Points
30
30
40
Fine Print
Make sure that all Java source files compile correctly!
A submission that contains source files that cannot be compiled will not count as a reasonable attempt.
To be sure, remove all *.class files and verify that javac X.java does not fail for any of your submission files X.java
(For TestVendingMachine this assumes that you have adjusted your CLASSPATH to include the junit and hamcrest dependencies
as mentioned in lecture 7b). You do not need to include these two .jar files in your submission.
Your submission is an individual piece of work. No collaboration with other students is allowed!
Expect that plagiarism detection software will be run on your submission to compare your work to that of other students.
Late submissions and plagiarism/collusion are subject to the University Code of Practice on Assessment.
In particular, since these are online submissions, a late penalty of 5% applies for every 24h period after the deadline.
Extensions requested after the submission deadline will not be granted.
Please get in touch with the student office to file a request for extenuating circumstances if necessary.
Do not define classes in any Java packages!
I am aware that it is generally good practice to keep your variable namespaces organized, and for that reason most IDEs will automatically suggest to do so by including a line
package yourProjectName;
or similar to every source file.
However, in order to automatically tests your submission we need to know the namespace where your classes are defined and the most fail-proof assumption is to use the default namespace, i.e., no packages.
If you don’t know what this is about, don’t worry and make sure your code does not contain any package declarations as above and compiles fine using javac *java in the directory that contains your files.