Skip to content

Commit 9038bf0

Browse files
committed
First commit to github
0 parents  commit 9038bf0

27 files changed

+552
-0
lines changed

README.txt

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Jonathan Lee - ThoughtWorks Submission: Problem Two Sales Taxes
2+
==========
3+
4+
Application Information:
5+
- Source code built in codio Online IDE
6+
- Written in Java:
7+
java version "1.7.0_67"
8+
- Tested with junit ver. 4.12
9+
10+
Instructions:
11+
+++++
12+
To run the application on Unix-like systems:
13+
1) From the command line, cd into the src directory of this application
14+
2) Compile the .java file by entering "javac SalesTaxApp.java"
15+
3) Run the compiled class file with "java SalesTaxApp ../test/testinput1.txt" (Or use any other text file provided, or your own)
16+
17+
To run tests:
18+
1) Download "junit-4.12.jar" and "hamcrest-core-1.3.jar", save these to the "src" directory
19+
2) Compile each test with the command "javac -cp junit-4.12.jar:hamcrest-core-1.3.jar:. <TESTJAVANAME>.java"
20+
3) The tests can be run individually with "java -cp junit-4.12.jar:hamcrest-core-1.3.jar:. org.junit.runner.JUnitCore <TESTCLASSNAME>"
21+
22+
For the entire testing suite:
23+
2) Compile with "javac -cp junit-4.12.jar:hamcrest-core-1.3.jar:. SalesTaxAppTestSuite.java"
24+
3) Run with "java -cp junit-4.12.jar:hamcrest-core-1.3.jar:. org.junit.runner.JUnitCore SalesTaxAppTestSuite"
25+
NOTE - This will run all the tests. But the individual tests will still need to be compiled to class files before the suite compilation will work.
26+
27+
Design Details:
28+
+++++
29+
- There are four main classes, the actual application (SalesTaxApp), Receipt, Good, and a FileReader
30+
- The file reader presents line-by-line information from text files in the form of String arrays
31+
- The Good is an object representation of items on the text list. There are getter methods for each field
32+
- The Receipt applies tax and can calculate the total price of items on its list
33+
- The application class ties together the above-mentioned classes and prints output to the console
34+
- Medicine and Food are classified by matching certain limited keyword to the name of the good.
35+
36+
Design Assumptions:
37+
+++++
38+
- File paths will be provided through command line args
39+
- The formatting of the items in the text file will always be "<Quantity> <Name> at <Price>/n"
40+
- The desired output should be printed to the console.
41+
42+
Date Submitted: 3/2/15

src/Good.class

547 Bytes
Binary file not shown.

src/Good.java

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
public class Good {
2+
private double price;
3+
private int quantity;
4+
private String name;
5+
6+
//Attributes can only be set in initialize
7+
public Good(int q, String n, double p) {
8+
quantity = q;
9+
name = n;
10+
price = p;
11+
}
12+
13+
public double getPrice() {
14+
return this.price;
15+
}
16+
17+
public int getQuantity() {
18+
return this.quantity;
19+
}
20+
21+
public String getName() {
22+
return this.name;
23+
}
24+
}

src/GoodTest.class

1.11 KB
Binary file not shown.

src/GoodTest.java

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import static org.junit.Assert.*;
2+
import org.junit.*;
3+
4+
public class GoodTest {
5+
private Good testGood;
6+
7+
@Before
8+
public void createTestGood() {
9+
testGood = new Good(3, "bottles of oxiclean", 19.95);
10+
}
11+
12+
@Test
13+
public void testGoodPrice() {
14+
double price = 19.95;
15+
assertEquals("Price of good is 19.95", price, testGood.getPrice(), 0.001);
16+
}
17+
18+
@Test
19+
public void testGoodQuantity() {
20+
int quantity = 3;
21+
assertEquals("Quantity of good is 3", quantity, testGood.getQuantity());
22+
}
23+
24+
@Test
25+
public void testGoodName() {
26+
String name = "bottles of oxiclean";
27+
assertEquals("Name of good is 'bottles of oxiclean'",name,testGood.getName());
28+
}
29+
}

src/HelloWorld.java

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import java.io.*;
2+
3+
public class HelloWorld{
4+
5+
public static void main(String []args){
6+
ByteArrayOutputStream os = new ByteArrayOutputStream();
7+
PrintStream ps = new PrintStream(os);
8+
PrintStream originalOut = System.out;
9+
10+
System.setOut(ps);
11+
12+
System.out.println("Nonono");
13+
14+
System.out.flush();
15+
System.setOut(originalOut);
16+
17+
System.out.println(ps.toString());
18+
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
19+
// PrintStream ps = new PrintStream(baos);
20+
// // IMPORTANT: Save the old System.out!
21+
// PrintStream old = System.out;
22+
// // Tell Java to use your special stream
23+
// System.setOut(ps);
24+
// // Print some output: goes to your special stream
25+
// System.out.println("Foofoofoo!");
26+
// // Put things back
27+
// System.out.flush();
28+
// System.setOut(old);
29+
// // Show what happened
30+
// System.out.println("Here: " + baos.toString());
31+
}
32+
}
33+
34+
//http://stackoverflow.com/questions/8708342/redirect-console-output-to-string-in-java

src/ReadFile.class

978 Bytes
Binary file not shown.

src/ReadFile.java

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import java.io.FileReader;
2+
import java.io.BufferedReader;
3+
import java.io.IOException;
4+
5+
6+
public class ReadFile {
7+
private String filepath;
8+
9+
//initializes with file path given, passes from command line args
10+
public ReadFile (String fp) {
11+
filepath = fp;
12+
}
13+
14+
public String[] openFile() throws IOException { //throws IOException to be handled in main application
15+
16+
FileReader fileread = new FileReader(filepath);
17+
BufferedReader textReader = new BufferedReader(fileread);
18+
19+
int numLines = numberOfLines(filepath);
20+
String[] textLineArray = new String[numLines];
21+
22+
for (int i = 0; i < numLines; i++) {
23+
textLineArray[i] = textReader.readLine();
24+
}
25+
26+
textReader.close();
27+
return textLineArray;
28+
}
29+
30+
//finds number of lines to instantiate Array
31+
private int numberOfLines(String path) throws IOException {
32+
FileReader targetFile = new FileReader(path);
33+
BufferedReader textStream = new BufferedReader(targetFile);
34+
35+
String line;
36+
int lineNumber = 0;
37+
38+
while ((line = textStream.readLine()) != null) {
39+
lineNumber++;
40+
}
41+
textStream.close();
42+
43+
return lineNumber;
44+
}
45+
46+
}

src/ReadFileTest.class

1.14 KB
Binary file not shown.

src/ReadFileTest.java

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import static org.junit.Assert.*;
2+
import org.junit.*;
3+
import java.io.IOException;
4+
5+
public class ReadFileTest {
6+
private ReadFile testReadFile;
7+
private String[] testStringArray;
8+
9+
@Before
10+
public void createFileReader() {
11+
testReadFile = new ReadFile("../test/readfiletest.txt");
12+
}
13+
14+
@Test
15+
public void fileReadStringArray() throws IOException {
16+
try{
17+
testStringArray = testReadFile.openFile();
18+
}
19+
catch (IOException e){
20+
System.out.println(e);
21+
}
22+
String[] correctOutput = {"Line 1","Line 2","Line 3"};
23+
assertArrayEquals("Creates String array from readfiletest.txt", correctOutput, testStringArray);
24+
}
25+
}

src/Receipt.class

1.85 KB
Binary file not shown.

src/Receipt.java

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
I cimport java.util.regex.Pattern;
2+
import java.util.regex.Matcher;
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class Receipt {
7+
private List<Good> goodsList;
8+
9+
public Receipt(List<Good> goods) {
10+
goodsList = goods;
11+
}
12+
13+
public List<Good> getList() {
14+
return goodsList;
15+
}
16+
17+
public Good getGood(int index) {
18+
Good goodBeforeTax = this.goodsList.get(index);
19+
double afterTax;
20+
21+
afterTax = goodBeforeTax.getPrice() + getTax(goodBeforeTax);
22+
double afterQuantity = afterTax * goodBeforeTax.getQuantity();
23+
24+
return new Good(goodBeforeTax.getQuantity(), goodBeforeTax.getName(),afterQuantity);
25+
}
26+
27+
public double getTotalTax() {
28+
double totalTax = 0;
29+
30+
for (int i=0;i<goodsList.size();i++) {
31+
Good listItem = goodsList.get(i);
32+
totalTax += getTax(listItem);
33+
}
34+
35+
return totalTax;
36+
}
37+
38+
public double getTotal() {
39+
double totalPrice = 0;
40+
41+
for (int i=0;i<goodsList.size();i++) {
42+
Good listItem = goodsList.get(i);
43+
totalPrice += listItem.getPrice();
44+
}
45+
46+
return totalPrice + getTotalTax();
47+
}
48+
49+
//The methods below are more like utility methods
50+
51+
private double getTax(Good item) {
52+
double tax = 0;
53+
54+
if (isImported(item.getName())) {
55+
tax += (item.getPrice() * 0.05);
56+
}
57+
58+
if (isTaxable(item.getName())) {
59+
tax += (item.getPrice() * 0.10);
60+
}
61+
62+
tax = (double) Math.ceil(tax*20.0)/20.0;
63+
64+
return tax;
65+
}
66+
67+
private boolean isImported(String name) {
68+
return name.contains("imported");
69+
}
70+
71+
private boolean isTaxable(String name) {
72+
Pattern taxExemptKeywords = Pattern.compile("chocolate|pill|book");
73+
Matcher hasExemptWords = taxExemptKeywords.matcher(name);
74+
75+
return !hasExemptWords.find();
76+
}
77+
}

src/ReceiptTest.class

2.45 KB
Binary file not shown.

src/ReceiptTest.java

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import static org.junit.Assert.*;
2+
import org.junit.*;
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class ReceiptTest {
7+
private List<Good> goodsList = new ArrayList<Good>();
8+
private Good testGood1;
9+
private Good testGood2;
10+
private Good testGood3;
11+
private Good testGood4;
12+
private Receipt testReceipt;
13+
14+
@Before
15+
public void createReceipt() {
16+
testGood1 = new Good(1,"hat",1.00);
17+
testGood2 = new Good(1,"imported hat",1.00);
18+
testGood3 = new Good(1,"chocolate hat",1.00);
19+
testGood4 = new Good(1,"imported chocolate hat",1.00);
20+
21+
goodsList.add(testGood1);
22+
goodsList.add(testGood2);
23+
goodsList.add(testGood3);
24+
goodsList.add(testGood4);
25+
26+
testReceipt = new Receipt(goodsList);
27+
}
28+
29+
//The different getGoodTests are less-than-ideal because they use methods tested in another area to return values. Ought to be refactored or the attributes exposed via reflection
30+
31+
@Test
32+
public void getGoodTest() {
33+
Good item = testReceipt.getGood(0);
34+
assertEquals("A hat should be 1.10", 1.10 , item.getPrice() , 0.001);
35+
assertEquals("Should have quantity of 1",1,item.getQuantity());
36+
assertEquals("Name is hat", "hat", item.getName());
37+
}
38+
39+
@Test
40+
public void getTaxExemptGoodTest() {
41+
Good item = testReceipt.getGood(2);
42+
assertEquals("A chocolate hat should be 1.00",1.00,item.getPrice(),0.001);
43+
assertEquals("Should have quantity of 1",1,item.getQuantity());
44+
assertEquals("Name is chocolate hat","chocolate hat",item.getName());
45+
}
46+
47+
@Test
48+
//This method reveals an interesting edge case, there is a very small trailing decimal that causes this method to fail. Need to refactor method in receipt method...
49+
public void getImportedGoodTest() {
50+
Good item = testReceipt.getGood(1);
51+
assertEquals("An imported hat should be 1.15",1.15,item.getPrice(), 0.001);
52+
assertEquals("Should have quantity of 1",1,item.getQuantity());
53+
assertEquals("Name is imported hat","imported hat",item.getName());
54+
}
55+
56+
@Test
57+
public void getImportedTaxExemptGoodTest() {
58+
Good item = testReceipt.getGood(3);
59+
assertEquals("A chocolate imported hat should be 1.05",1.05,item.getPrice(), 0.001);
60+
assertEquals("Should have quantity of 1",1,item.getQuantity());
61+
assertEquals("Name is imported chocolate hat","imported chocolate hat",item.getName());
62+
}
63+
64+
@Test
65+
public void getTotalTaxTest() {
66+
assertEquals("Sales tax should be 0.30",0.30,testReceipt.getTotalTax(),0.001);
67+
}
68+
69+
@Test
70+
public void getTotalTest() {
71+
assertEquals("Total price should be 4.35",4.35,testReceipt.getTotal(),0.001);
72+
}
73+
}

0 commit comments

Comments
 (0)