diff --git a/src/Spreadsheet.java b/src/Spreadsheet.java index e4f120b..4f90980 100644 --- a/src/Spreadsheet.java +++ b/src/Spreadsheet.java @@ -1,18 +1,192 @@ +import java.util.ArrayList; +import java.util.HashMap; public class Spreadsheet { + + private static final String error = "#Error"; + private static final String circular = "#Circular"; + + private HashMap spreadSheet = new HashMap(); + private ArrayList nodes = new ArrayList(); public String get(String cell) { - // to be implemented - return null; + String val = spreadSheet.get(cell); + if (val != null) { + if (isValidString(val)) { + val = stripStringTags(val); + } + else if (isFormula(val)) { + val = handleFormula(cell, val); + } + } + if (val != circular && nodes.contains(cell)) { + nodes.remove(cell); + } + return val; + } + + private String handleFormula(String cell, String val) { + if (isValidCalculation(val.substring(1))) { + val = calculate(val.substring(1)); + } + else if (isReference(val.substring(1))) { + if (!nodes.contains(cell)) { + nodes.add(cell); + } + else { + val = circular; + } + } + if (val != circular && !isValidInteger(val)) { + val = evaluate(val.substring(1)); + } + return val; + } + + private boolean isFormula(String val) { + if (val.startsWith("=")) { + return true; + } + return false; + } + + private String stripStringTags(String val) { + val = val.replace("'", ""); + val = val.replace("&", ""); + return val; } public void set(String cell, String value) { - // to be implemented + if (isValidInteger(value) || isValidString(value) || isFormula(value) || isValidCalculation(value)) { + spreadSheet.put(cell, value); + } + else { + spreadSheet.put(cell, error); + } } + private boolean isValidString(String value) { + if (value.startsWith("'") && value.endsWith("'")) { + return true; + } + return false; + } + + private boolean isValidInteger(String value) { + try { + Integer.parseInt(value); + return true; + } catch (NumberFormatException e) { + return false; + } + } + public String evaluate(String cell) { - // to be implemented - return null; + String val = cell; + if (isValidString(val)) { + if (hasStringOperation(val)) { + val = performStringOperation(val); + } + else { + val = stripStringTags(val); + } + } + else if (isValidInteger(val)) { + // do nothing + } + else if (isReference(val)) { + val = this.get(val); + } + else { + return error; + } + return val; + } + + private String performStringOperation(String val) { + String[] strings = val.split("&"); + String word; + String phrase = ""; + for (int i = 0; i < strings.length; i++) { + word = this.evaluate(strings[i]); + phrase = phrase.concat(word); + if (word == error) { + phrase = error; + break; + } + } + return phrase; + } + + private boolean hasStringOperation(String val) { + if (val.indexOf("&") != -1) { + return true; + } + return false; + } + + private String calculate(String cell) { + String operations = "+"; + int result = 0; + int val; + char operation; + String[] values = cell.split("[-+*/%]"); + operations += cell.replaceAll("\\w", ""); + for (int i = 0; i < values.length; i++) { + operation = operations.charAt(i); + if (isValidInteger(values[i])) { + val = Integer.parseInt(values[i]); + } + else { + val = Integer.parseInt(this.get(values[i])); + } + result = performOperation(result, val, operation); + } + return Integer.toString(result); + } + + private int performOperation(int result, int val, char operation) { + if (operation == '+') { + result += val; + } + else if (operation == '-') { + result -= val; + } + else if (operation == '*') { + result *= val; + } + else if (operation == '/') { + result /= val; + } + else if (operation == '%') { + result %= val; + } + return result; + } + + private boolean isValidCalculation(String cell) { + String[] values = cell.split("[-+*/%]"); + if (values.length > 1) { + for (int i = 0; i < values.length; i++) { + if (!isValidInteger(values[i]) && !isValidInteger(this.get(values[i]))) { + return false; + } + } + return true; + } + else { + return false; + } + } + + private boolean isReference(String cell) { + if (isValidInteger(cell) || isValidString(cell)) { + return false; + } + if (Character.isLetter(cell.charAt(0)) && Character.isDigit(cell.charAt(1))) { + return true; + } + return false; } } diff --git a/tests/SpreadsheetTest.java b/tests/SpreadsheetTest.java index 9e0936a..4a40166 100644 --- a/tests/SpreadsheetTest.java +++ b/tests/SpreadsheetTest.java @@ -5,11 +5,150 @@ public class SpreadsheetTest { + + Spreadsheet sheet = new Spreadsheet(); @Test - public void test() { - fail("Not yet implemented"); - + public void SpreadsheetTest_assign_get_val() { + sheet.set("A1", "-1"); + String val = sheet.get("A1"); + assertEquals("-1", val); } + + @Test + public void SpreadsheetTest_assign_get_wrong_format_int() { + sheet.set("A1", "5A"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_assign_get_valid_string() { + sheet.set("A1", "'a string'"); + String val = sheet.get("A1"); + assertEquals("a string", val); + } + + @Test + public void SpreadsheetTest_assign_get_invalid_string() { + sheet.set("A1", "'a string"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_assign_formula_get_valid_string() { + sheet.set("A1", "='a string'"); + String val = sheet.get("A1"); + assertEquals("a string", val); + } + + @Test + public void SpreadsheetTest_assign_formula_get_invalid_string() { + sheet.set("A1", "='a string"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_assign_formula_get_valid_reference() { + sheet.set("A1", "='a string'"); + sheet.set("A2", "=A1"); + String val = sheet.get("A2"); + assertEquals("a string", val); + } + + @Test + public void SpreadsheetTest_assign_int_ref_get() { + sheet.set("A1", "5"); + sheet.set("A2", "=A1"); + String val = sheet.get("A2"); + assertEquals("5", val); + } + + @Test + public void SpreadsheetTest_assign_circular_reference_get() { + sheet.set("A1", "=A2"); + sheet.set("A2", "=A1"); + String val = sheet.get("A1"); + assertEquals("#Circular", val); + } + + @Test + public void SpreadsheetTest_invalid_calculation() { + sheet.set("A1", "10"); + sheet.set("A2", "5"); + sheet.set("A3", "asdf"); + sheet.set("A4", "A1+A2+A3"); + String val = sheet.get("A4"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_valid_sum_calculation() { + sheet.set("A1", "10"); + sheet.set("A2", "5"); + sheet.set("A3", "4"); + sheet.set("A4", "=A1+A2+A3"); + String val = sheet.get("A4"); + assertEquals("19", val); + } + + @Test + public void SpreadsheetTest_valid_sum_calculation_with_ref() { + sheet.set("A1", "10"); + sheet.set("A2", "5"); + sheet.set("A3", "=A1"); + sheet.set("A4", "=A1+A2+A3"); + String val = sheet.get("A4"); + assertEquals("25", val); + } + + @Test + public void SpreadsheetTest_ref_error() { + sheet.set("A5", "5A"); + sheet.set("A1", "=A5"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_valid_mul_calculation() { + sheet.set("A1", "1"); + sheet.set("A2", "1"); + sheet.set("A3", "3"); + sheet.set("A4", "=A1+A2*A3"); + String val = sheet.get("A4"); + assertEquals("6", val); + } + + @Test + public void SpreadsheetTest_calc_error() { + sheet.set("A1", "1+A1"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + + @Test + public void SpreadsheetTest_simple_calc() { + sheet.set("A1", "=1+2"); + String val = sheet.get("A1"); + assertEquals("3", val); + } + + @Test + public void SpreadsheetTest_string_concat() { + sheet.set("A1", "='a'&'string'"); + String val = sheet.get("A1"); + assertEquals("astring", val); + } + + @Test + public void SpreadsheetTest_string_concat_invalid() { + sheet.set("A1", "='a&'string'"); + String val = sheet.get("A1"); + assertEquals("#Error", val); + } + }