diff --git a/src/Spreadsheet.java b/src/Spreadsheet.java index e4f120b..a537934 100644 --- a/src/Spreadsheet.java +++ b/src/Spreadsheet.java @@ -1,18 +1,146 @@ +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; public class Spreadsheet { + + private static final String CIRCULAR_TAG = "#Circular"; + private static final String ERROR_TAG = "#Error"; + HashMap> cell_entries = new HashMap<>(); + Set references; + boolean circularDetected = false; public String get(String cell) { - // to be implemented - return null; + return concatSubEntries(cell_entries.get(cell)); } public void set(String cell, String value) { - // to be implemented + cell_entries.put(cell, createSubEntries(value)); } public String evaluate(String cell) { - // to be implemented - return null; + references = new HashSet<>(); + List evaluatedSubEntries = new LinkedList<>(); + for (SubEntry se : cell_entries.get(cell)) { + String evaluatedSubEntry = evaluateSubEntry(se); + if (evaluatedSubEntry.equals(ERROR_TAG)) + return ERROR_TAG; + else + evaluatedSubEntries.add(evaluatedSubEntry); + + if (circularDetected) { + return CIRCULAR_TAG; + } + } + String cell_entry = concatStrings(evaluatedSubEntries); + + return cell_entry; + } + + public String evaluateSubEntry(SubEntry se) { + if (se.getType() == SubEntryType.NUMBER && ! isNum(se.getValue())) { + return ERROR_TAG; + } else if (se.getType() == SubEntryType.REFERENCE) { + if (references.contains(Integer.valueOf(se.getValue()))) { + circularDetected = true; + return CIRCULAR_TAG; + } else { + references.add(Integer.valueOf(se.getValue())); + return evaluate("A" + se.getValue()); + } + } else { + return se.getValue(); + } + } + + public String concatSubEntries(List subEntries) { + String res = ""; + for (SubEntry se : subEntries) { + res += se.getValue(); + } + return res; + } + + public String concatStrings(List strings) { + String res = ""; + for (String s : strings) { + res += s; + } + return res; + } + + public List createSubEntries(String cell) { + List subEntries = new LinkedList<>(); + String intSubEntry = ""; + String strSubEntry = ""; + String refValue = ""; + boolean quotesOpen = false; + boolean refToCell = false; + + for (int i = 0; i < cell.toCharArray().length; i++) { + char c = cell.toCharArray()[i]; + + // Check for "=" at the beginning of the cell value + if (i == 0 && c == '=') + continue; + + if (refToCell) { + if (c != ' ') { + refValue += c; + } else { + refToCell = false; + subEntries.add(new SubEntry(refValue, SubEntryType.REFERENCE)); + refValue = ""; + } + } else if (quotesOpen == false) { + if (c == 'A') { + refToCell = true; + if (intSubEntry != "" || strSubEntry != "") { + subEntries.add(new SubEntry(ERROR_TAG, SubEntryType.ERROR)); + intSubEntry = ""; + strSubEntry = ""; + } + } else if (c != '\'') { + intSubEntry += c; + } else { + if (intSubEntry != "") + subEntries.add(new SubEntry(intSubEntry, SubEntryType.NUMBER)); + intSubEntry = ""; + quotesOpen = true; + } + } else { + if (c != '\'') { + strSubEntry += c; + } else { + subEntries.add(new SubEntry(strSubEntry, SubEntryType.STRING)); + strSubEntry = ""; + quotesOpen = false; + } + } + } + if (intSubEntry != "") + subEntries.add(new SubEntry(intSubEntry, SubEntryType.NUMBER)); + if (strSubEntry != "") + subEntries.add(new SubEntry(ERROR_TAG, SubEntryType.ERROR)); + if (refToCell == true) { + if (refValue != "") + subEntries.add(new SubEntry(refValue, SubEntryType.REFERENCE)); + else + subEntries.add(new SubEntry(ERROR_TAG, SubEntryType.ERROR)); + } + + return subEntries; + } + + public boolean isNum(String s) { + try { + Integer.valueOf(s); + } catch (NumberFormatException ex) { + return false; + } + return true; } } diff --git a/src/SubEntry.java b/src/SubEntry.java new file mode 100644 index 0000000..4aa4666 --- /dev/null +++ b/src/SubEntry.java @@ -0,0 +1,27 @@ + +public class SubEntry { + private String value; + private SubEntryType type; + + public SubEntry(String value, SubEntryType type) { + this.value = value; + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public SubEntryType getType() { + return type; + } + + public void setType(SubEntryType type) { + this.type = type; + } + +} diff --git a/src/SubEntryType.java b/src/SubEntryType.java new file mode 100644 index 0000000..5021971 --- /dev/null +++ b/src/SubEntryType.java @@ -0,0 +1,4 @@ + +public enum SubEntryType { + NUMBER, STRING, REFERENCE, ERROR +} diff --git a/tests/SpreadsheetTest.java b/tests/SpreadsheetTest.java index 9e0936a..8e0f39d 100644 --- a/tests/SpreadsheetTest.java +++ b/tests/SpreadsheetTest.java @@ -1,15 +1,121 @@ import static org.junit.Assert.*; +import java.util.List; import org.junit.Test; public class SpreadsheetTest { + private static final String CIRCULAR_TAG = "#Circular"; + private static final String ERROR_TAG = "#Error"; + Spreadsheet spreadSheet = new Spreadsheet(); - @Test - public void test() { - fail("Not yet implemented"); - + + /* + * 1 + */ + + @Test public void testSpreadsheet_SetA1_1_GetA1_String_1() { + spreadSheet.set("A1", "1"); + assertEquals("1", spreadSheet.get("A1")); + } + + + /* + * 2 + */ + + @Test public void testSpreadsheet_SetA1_1_EvalA1_String_1() { + spreadSheet.set("A1", "1"); + assertEquals("1", spreadSheet.evaluate("A1")); + } + + + /* + * 3 + */ + + @Test public void testSpreadsheet_SetA1_A5_EvalA1_ErrorString() { + spreadSheet.set("A1", "5A"); + assertEquals(ERROR_TAG, spreadSheet.evaluate("A1")); + } + + + /* + * 4 + */ + + @Test public void testSpreadsheet_SetA1_String_EvalA1_StringWithoutQuotes() { + spreadSheet.set("A1", "'a string'"); + assertEquals("a string", spreadSheet.evaluate("A1")); + } + + + /* + * 5 + */ + + @Test public void testSpreadsheet_SetA1WrongQuotedString_EvalA1_Error() { + spreadSheet.set("A1", "'a string"); + assertEquals(ERROR_TAG, spreadSheet.evaluate("A1")); + } + + + /* + * 6 + */ + + @Test public void testSpreadSheet_SetA1_EqualSignBeforeString_EvalA1_OnlyString() { + spreadSheet.set("A1", "='a string'"); + assertEquals("a string", spreadSheet.evaluate("A1")); + } + + + /* + * 7 + */ + + @Test public void testSpreadsheet_SetA1_EqualSignAndWrongQuotedString_EvalA1_Error() { + spreadSheet.set("A1", "='a string"); + assertEquals(ERROR_TAG, spreadSheet.evaluate("A1")); + } + + + /* + * 8 + */ + + @Test public void testSpreadSheet_createOneSubEntryWithReference_TypeOfSubEntry_REFERENCE() { + List subEntries = spreadSheet.createSubEntries("=A5"); + assertEquals(SubEntryType.REFERENCE, subEntries.get(0).getType()); + } + + @Test public void testSpreadSheet_Set_A5_5_And_A1_EqualA5_EvalA1_5() { + spreadSheet.set("A5", "5"); + spreadSheet.set("A1", "=A5"); + assertEquals("5", spreadSheet.evaluate("A1")); + } + + + /* + * 9 + */ + + @Test public void testSpreadSheet_Set_A5_5A_And_A1_EqualA5_EvalA1_Error() { + spreadSheet.set("A5", "5A"); + spreadSheet.set("A1", "=A5"); + assertEquals(ERROR_TAG, spreadSheet.evaluate("A1")); + } + + + /* + * 10 + */ + + @Test public void testSpreadSheet_Set_A5_EqualA1_And_A1_EqualA5_EvalA1_CircularTag() { + spreadSheet.set("A5", "=A1"); + spreadSheet.set("A1", "=A5"); + assertEquals(CIRCULAR_TAG, spreadSheet.evaluate("A1")); } }