aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.idea/checkstyle-idea.xml26
-rw-r--r--.idea/libraries/javatuples.xml12
-rw-r--r--.idea/modules.xml2
-rw-r--r--.idea/uiDesigner.xml124
-rw-r--r--apus.iml (renamed from Project-Starter.iml)7
-rw-r--r--data/example.css25
-rw-r--r--data/example.html46
-rw-r--r--data/example.md39
-rw-r--r--data/tobs.jpgbin314309 -> 0 bytes
-rw-r--r--src/main/model/MyModel.java5
-rw-r--r--src/main/model/css/CssLexer.java63
-rw-r--r--src/main/model/html/HtmlLexer.java68
-rw-r--r--src/main/model/util/AbstractTree.java35
-rw-r--r--src/main/model/util/Lexer.java58
-rw-r--r--src/test/model/CssLexerTest.java67
-rw-r--r--src/test/model/HtmlLexerTest.java69
-rw-r--r--src/test/model/MyModelTest.java7
17 files changed, 623 insertions, 30 deletions
diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml
index 551b800..eda52d4 100644
--- a/.idea/checkstyle-idea.xml
+++ b/.idea/checkstyle-idea.xml
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="CheckStyle-IDEA">
- <option name="configuration">
- <map>
- <entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/checkstyle.xml:CPSC 210 Checkstyle" />
- <entry key="checkstyle-version" value="8.18" />
- <entry key="copy-libs" value="false" />
- <entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
- <entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
- <entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/checkstyle.xml:CPSC 210 Checkstyle" />
- <entry key="scan-before-checkin" value="false" />
- <entry key="scanscope" value="JavaOnly" />
- <entry key="suppress-errors" value="false" />
- </map>
+ <component name="CheckStyle-IDEA" serialisationVersion="2">
+ <checkstyleVersion>8.18</checkstyleVersion>
+ <scanScope>JavaOnly</scanScope>
+ <option name="thirdPartyClasspath" />
+ <option name="activeLocationIds">
+ <option value="5ed4fe78-33b5-4a2f-9159-da0cbae12bec" />
+ </option>
+ <option name="locations">
+ <list>
+ <ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
+ <ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
+ <ConfigurationLocation id="5ed4fe78-33b5-4a2f-9159-da0cbae12bec" type="PROJECT_RELATIVE" scope="All" description="CPSC 210 Checkstyle">$PROJECT_DIR$/checkstyle.xml</ConfigurationLocation>
+ </list>
</option>
</component>
</project> \ No newline at end of file
diff --git a/.idea/libraries/javatuples.xml b/.idea/libraries/javatuples.xml
new file mode 100644
index 0000000..adca311
--- /dev/null
+++ b/.idea/libraries/javatuples.xml
@@ -0,0 +1,12 @@
+<component name="libraryTable">
+ <library name="javatuples" type="repository">
+ <properties maven-id="org.javatuples:javatuples:1.2" />
+ <CLASSES>
+ <root url="jar://$MAVEN_REPOSITORY$/org/javatuples/javatuples/1.2/javatuples-1.2.jar!/" />
+ </CLASSES>
+ <JAVADOC>
+ <root url="jar://$MAVEN_REPOSITORY$/org/javatuples/javatuples/1.2/javatuples-1.2-javadoc.jar!/" />
+ </JAVADOC>
+ <SOURCES />
+ </library>
+</component> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 7ac8932..7045e98 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
- <module fileurl="file://$PROJECT_DIR$/Project-Starter.iml" filepath="$PROJECT_DIR$/Project-Starter.iml" />
+ <module fileurl="file://$PROJECT_DIR$/apus.iml" filepath="$PROJECT_DIR$/apus.iml" />
</modules>
</component>
</project> \ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+</project> \ No newline at end of file
diff --git a/Project-Starter.iml b/apus.iml
index 08bb910..19129c3 100644
--- a/Project-Starter.iml
+++ b/apus.iml
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
- <component name="CheckStyle-IDEA-Module">
- <option name="configuration">
- <map />
- </option>
+ <component name="CheckStyle-IDEA-Module" serialisationVersion="2">
+ <option name="activeLocationsIds" />
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
@@ -29,5 +27,6 @@
<SOURCES />
</library>
</orderEntry>
+ <orderEntry type="library" name="javatuples" level="project" />
</component>
</module> \ No newline at end of file
diff --git a/data/example.css b/data/example.css
new file mode 100644
index 0000000..dd93d52
--- /dev/null
+++ b/data/example.css
@@ -0,0 +1,25 @@
+body {
+ background-color: #f0f0f2;
+ margin: 0;
+ padding: 0;
+ font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+}
+div {
+ width: 600px;
+ margin: 5em auto;
+ padding: 2em;
+ background-color: #fdfdff;
+ border-radius: 0.5em;
+ box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
+}
+a:link, a:visited {
+ color: #38488f;
+ text-decoration: none;
+}
+@media (max-width: 700px) {
+ div {
+ margin: 0 auto;
+ width: auto;
+ }
+}
diff --git a/data/example.html b/data/example.html
new file mode 100644
index 0000000..b62fc42
--- /dev/null
+++ b/data/example.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Example Domain</title>
+
+ <meta charset="utf-8" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <style type="text/css">
+ body {
+ background-color: #f0f0f2;
+ margin: 0;
+ padding: 0;
+ font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+ }
+ div {
+ width: 600px;
+ margin: 5em auto;
+ padding: 2em;
+ background-color: #fdfdff;
+ border-radius: 0.5em;
+ box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
+ }
+ a:link, a:visited {
+ color: #38488f;
+ text-decoration: none;
+ }
+ @media (max-width: 700px) {
+ div {
+ margin: 0 auto;
+ width: auto;
+ }
+ }
+ </style>
+</head>
+
+<body>
+<div>
+ <h1>Example Domain</h1>
+ <p>This domain is for use in illustrative examples in documents. You may use this
+ domain in literature without prior coordination or asking for permission.</p>
+ <p><a href="https://www.iana.org/domains/example">More information...</a></p>
+</div>
+</body>
+</html>
diff --git a/data/example.md b/data/example.md
new file mode 100644
index 0000000..45b29de
--- /dev/null
+++ b/data/example.md
@@ -0,0 +1,39 @@
+Heading
+=======
+
+Sub-heading
+-----------
+
+# Alternative heading #
+
+Paragraphs are separated
+by a blank line.
+
+Two spaces at the end of a line
+produce a line break.
+
+Text attributes _italic_, **bold**, `monospace`.
+
+Horizontal rule:
+
+---
+
+Bullet lists nested within numbered list:
+
+1. fruits
+ * apple
+ * banana
+2. vegetables
+ - carrot
+ - broccoli
+
+A [link](http://example.com).
+
+![Image](Icon-pictures.png "icon")
+
+> Markdown uses email-style
+characters for blockquoting.
+>
+> Multiple paragraphs need to be prepended individually.
+
+Most inline <abbr title="Hypertext Markup Language">HTML</abbr> tags are supported. \ No newline at end of file
diff --git a/data/tobs.jpg b/data/tobs.jpg
deleted file mode 100644
index f1652ef..0000000
--- a/data/tobs.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/model/MyModel.java b/src/main/model/MyModel.java
deleted file mode 100644
index f9a3dd7..0000000
--- a/src/main/model/MyModel.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package model;
-
-public class MyModel {
- // delete or rename this class!
-}
diff --git a/src/main/model/css/CssLexer.java b/src/main/model/css/CssLexer.java
new file mode 100644
index 0000000..657d3e1
--- /dev/null
+++ b/src/main/model/css/CssLexer.java
@@ -0,0 +1,63 @@
+package model.css;
+
+import java.util.ArrayList;
+
+/**
+ * This lexer splits an input by whitespace, brackets, and semicolons.
+ * Brackets and semicolons are included in the lexed output, whitespace is not.
+ * <br>
+ * CSS, thankfully, is far more rigid and less-forgiving of errors than HTMl.
+ * It also has multiple layers of fallback for errors: ranging from: "ignore this
+ * property", to "ignore this rule", to "this isn't fucking CSS" and ignore it all.
+ * <br>
+ * Still, even though we don't have to deal with garbage like escaped quotes (future edit: whoops, yes we do) and
+ * what not, we'll still implement our lexer with a for loop instead of split() for future optimizations.
+ */
+public class CssLexer {
+
+ public static ArrayList<String> lex(String input) {
+ String token = "";
+ ArrayList<String> tokens = new ArrayList<>();
+ boolean inSingleQuotes = false;
+ boolean inDoubleQuotes = false;
+ char previous = '\0';
+
+ for (char i : input.toCharArray()) {
+ // i HATE fallthrough switch statements
+ switch (i) {
+ case '{': case '}': case ';': case ':':
+ case ' ': case '\n': case '\t':
+ if (!inSingleQuotes && !inDoubleQuotes) {
+ if (!token.equals("")) {
+ tokens.add(token);
+ token = "";
+ }
+ switch (i) {
+ case '{': case '}': case ';': case ':':
+ tokens.add(Character.toString(i));
+ break;
+ case ' ': case '\n': case '\t':
+ break;
+ }
+ } else {
+ token += i;
+ }
+ break;
+ // intentional use of footgun behavior
+ case '"':
+ if (previous != '\\') {
+ inDoubleQuotes = !inDoubleQuotes;
+ }
+ case '\'':
+ if (previous != '\\') {
+ inSingleQuotes = !inSingleQuotes;
+ }
+ default:
+ token += i;
+ break;
+ }
+ previous = i;
+ }
+ return tokens;
+ }
+}
diff --git a/src/main/model/html/HtmlLexer.java b/src/main/model/html/HtmlLexer.java
new file mode 100644
index 0000000..8cad425
--- /dev/null
+++ b/src/main/model/html/HtmlLexer.java
@@ -0,0 +1,68 @@
+package model.html;
+
+import java.util.ArrayList;
+
+/**
+ * We'll tokenize HTML by tags: disregarding the contents of the tag and attributes within the tag.
+ * The file is also considered to be free-form here: whitespace duplicates are disregarded.
+ */
+public class HtmlLexer {
+
+ // Takes a String of raw HTML, and tokenizes it for our parser.
+ public static ArrayList<String> lex(String input) {
+ String token = "";
+ ArrayList<String> tokens = new ArrayList<>();
+ boolean inTag = false;
+ boolean inSingleQuotes = false;
+ boolean inDoubleQuotes = false;
+
+ for (char i : input.toCharArray()) {
+ token += i;
+ switch (i) {
+ case '<':
+ if (!inSingleQuotes && !inDoubleQuotes) {
+ inTag = true;
+ if (!token.equals("<")) {
+ tokens.add(token.substring(0, token.length() - 1));
+ token = "<";
+ }
+ } else if (inTag) {
+ System.out.printf("Probably failing parser");
+ }
+ break;
+ case '>':
+ if (!inSingleQuotes && !inDoubleQuotes) {
+ if (!inTag) {
+ System.out.printf("Probably failing parser");
+ }
+ inTag = false;
+ tokens.add(token);
+ token = "";
+ }
+ break;
+ case '"':
+ if (!inSingleQuotes) {
+ inDoubleQuotes = !inDoubleQuotes;
+ }
+ break;
+ case '\'':
+ if (!inDoubleQuotes) {
+ inSingleQuotes = !inSingleQuotes;
+ }
+ break;
+ }
+ }
+ /**
+ * When lexing invalid HTML: we may end up with trailing garbage: either an unfinished tag or extra text
+ * (those are the only two options since this is just the lex step)
+ */
+ if (!token.equals("")) {
+ if (inTag) {
+ tokens.add(token + ">");
+ } else {
+ tokens.add(token);
+ }
+ }
+ return tokens;
+ }
+}
diff --git a/src/main/model/util/AbstractTree.java b/src/main/model/util/AbstractTree.java
new file mode 100644
index 0000000..4c74732
--- /dev/null
+++ b/src/main/model/util/AbstractTree.java
@@ -0,0 +1,35 @@
+package model.util;
+
+import org.javatuples.*;
+
+import java.util.*;
+
+// Utility class for a general tree: we'll be using these a lot
+public abstract class AbstractTree<T> {
+
+ // An AbstractTree holds some kind of data; we'll want this to be generic
+ // e.g. a tag, attributes, a tag and attributes, etc
+ private T data;
+ // Since it's a tree every node also has children.
+ private ArrayList<AbstractTree<T>> children;
+
+ // future implementations may want to consider adding an Optional<> parent; or an Optional<> prevSibling
+
+ public T getData() {
+ return data;
+ }
+
+ public ArrayList<AbstractTree<T>> getChildren() {
+ return children;
+ }
+
+ // god so much boilerplate
+ public AbstractTree(T data, ArrayList<AbstractTree<T>> children) {
+ this.data = data;
+ this.children = children;
+ }
+
+ public void addChild(AbstractTree<T> child) {
+ this.children.add(child);
+ }
+}
diff --git a/src/main/model/util/Lexer.java b/src/main/model/util/Lexer.java
new file mode 100644
index 0000000..b35caa6
--- /dev/null
+++ b/src/main/model/util/Lexer.java
@@ -0,0 +1,58 @@
+package model.util;
+
+import java.util.*;
+
+// General-purpose Lexer
+public class Lexer {
+
+ // private static final Set<String> whitespace = new HashSet<String>(" ", "\n");
+
+ // unused, helper function for if we implement finding identifers longer than a character
+ private static int longestDelimiter(Set<String> delimiters) {
+ int longestDelimiter = 0;
+ for (String delimiter : delimiters) {
+ if (delimiter.length() > longestDelimiter) {
+ longestDelimiter = delimiter.length();
+ }
+ }
+ return longestDelimiter;
+ }
+
+ /**
+ * Lexes a "free-form" language. "free-form" has a specific meaning here that's important to preserve:
+ * "free-form" means that _additional_ whitespace characters do not affect the language: e.g. two newlines
+ * instead of one, four spaces instead of two, etc. They are _not_ "whitespace-insensitive", which is usually
+ * a misnomer.
+ * The name's a bit of a joke: free-form languages are generally referred to as whitespace-insensitive -->
+ * insensitive == rude. Jokes are funnier when you have to explain them.
+ * Also, insensitiveLex() and freeformLex() aren't really that good of names.
+ *
+ * NOTE: This lexer only works with single-character deliminators.
+ * TODO: deduplicate whitespace
+ */
+ // public static ArrayList<String> rudeLex(String input, Set<Character> delimiters) {}
+
+ /**
+ * We might as well implement a lexer for non-free-form languages, but whatever. We won't use it.
+ */
+ public static ArrayList<String> sensitiveLex(String input, Set<Character> delimiters) {
+ // int longestDelimiter = longestDelimiter(delimiters);
+
+ ArrayList<String> tokens = new ArrayList<String>();
+ String currentToken = "";
+ // terrible c-style for loop because we may need to manipulate the index in the future
+ for (int i = 0; i < input.length(); i++) {
+ char nextToken = input.charAt(i);
+ if (delimiters.contains(nextToken)) {
+ if (!currentToken.equals("")) {
+ tokens.add(currentToken);
+ }
+ tokens.add(Character.toString(nextToken));
+ currentToken = "";
+ } else {
+ currentToken += input.charAt(i);
+ }
+ }
+ return tokens;
+ }
+}
diff --git a/src/test/model/CssLexerTest.java b/src/test/model/CssLexerTest.java
new file mode 100644
index 0000000..4ed28e2
--- /dev/null
+++ b/src/test/model/CssLexerTest.java
@@ -0,0 +1,67 @@
+package model;
+
+import model.css.CssLexer;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class CssLexerTest {
+
+ @Test
+ void testIdiomaticHtml() {
+ try {
+ String idiomaticCss = Files.readString(Path.of("data/example.css"));
+ String[] expected = {"body", "{", "background-color", ":", "#f0f0f2", ";", "margin", ":", "0", ";", "padding", ":", "0", ";", "font-family", ":", "-apple-system,", "system-ui,", "BlinkMacSystemFont,", "\"Segoe UI\",", "\"Open Sans\",", "\"Helvetica Neue\",", "Helvetica,", "Arial,", "sans-serif", ";", "}", "div", "{", "width", ":", "600px", ";", "margin", ":", "5em", "auto", ";", "padding", ":", "2em", ";", "background-color", ":", "#fdfdff", ";", "border-radius", ":", "0.5em", ";", "box-shadow", ":", "2px", "3px", "7px", "2px", "rgba(0,0,0,0.02)", ";", "}", "a", ":", "link,", "a", ":", "visited", "{", "color", ":", "#38488f", ";", "text-decoration", ":", "none", ";", "}", "@media", "(max-width", ":", "700px)", "{", "div", "{", "margin", ":", "0", "auto", ";", "width", ":", "auto", ";", "}", "}"};
+
+ assertEquals(CssLexer.lex(idiomaticCss), Arrays.asList(expected));
+ for (String i : CssLexer.lex(idiomaticCss)) {
+ System.out.print("\"");
+ System.out.print(i);
+ System.out.print("\", ");
+ }
+ } catch (IOException e) {
+ System.out.printf("fuck %s\n", e.toString());
+ System.out.println(System.getProperty("user.dir"));
+ }
+ }
+/**
+ FoodServicesCard c1;
+ FoodServicesCard c2;
+ FoodServicesCard c3;
+
+ @BeforeEach
+ void runBefore() {
+ c1 = new FoodServicesCard(0);
+ c2 = new FoodServicesCard(100);
+ c3 = new FoodServicesCard(2000);
+ }
+
+ @Test
+ void testReloadingAndPurchasing() {
+ assertFalse(c1.makePurchase(100));
+ assertEquals(c1.getBalance(), 0);
+ c2.reload(10);
+ assertEquals(c2.getBalance(), 110);
+ assertTrue(c3.makePurchase(1400));
+ assertEquals(c3.getBalance(), 600);
+ }
+
+ @Test
+ void testRewardPoints() {
+ if (c1.makePurchase(c1.POINTS_NEEDED_FOR_CASH_BACK / 2)) {
+ assertEquals(c1.getRewardPoints(), (c1.POINTS_NEEDED_FOR_CASH_BACK / 2));
+ } else {
+ assertEquals(c1.getRewardPoints(), 0);
+ }
+ c2.makePurchase(c2.POINTS_NEEDED_FOR_CASH_BACK);
+ assertEquals(c2.getRewardPoints(), 0);
+ c3.makePurchase(1200);
+ assertEquals(c3.getRewardPoints(), 1200 % c3.POINTS_NEEDED_FOR_CASH_BACK);
+ }
+ */
+} \ No newline at end of file
diff --git a/src/test/model/HtmlLexerTest.java b/src/test/model/HtmlLexerTest.java
new file mode 100644
index 0000000..9dd5574
--- /dev/null
+++ b/src/test/model/HtmlLexerTest.java
@@ -0,0 +1,69 @@
+package model;
+
+import model.html.HtmlLexer;
+
+import org.junit.jupiter.api.*;
+
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HtmlLexerTest {
+ String idiomaticHtml = "<!DOCTYPE html><html><head></head><body><p>Hello,world!</p></body></html>";
+ String brokenHtml = "<html><foo><bar></bar><ba";
+ String trailingTextHtml = "<html><foo><bar></bar>ba";
+
+ @Test
+ void testIdiomaticHtml() {
+ String[] idiomaticHtmlArray = {"<!DOCTYPE html>","<html>","<head>","</head>","<body>","<p>","Hello,world!","</p>","</body>","</html>"};
+ assertEquals(HtmlLexer.lex(idiomaticHtml), Arrays.asList(idiomaticHtmlArray));
+ }
+
+ @Test
+ void testBrokenHtml() {
+ String[] brokenHtmlArray = {"<html>","<foo>","<bar>","</bar>","<ba>"};
+ assertEquals(HtmlLexer.lex(brokenHtml), Arrays.asList(brokenHtmlArray));
+ }
+
+ @Test
+ void testTrailingTextHtml() {
+ String[] trailingTextHtmlArray = {"<html>","<foo>","<bar>","</bar>","ba"};
+ assertEquals(HtmlLexer.lex(trailingTextHtml), Arrays.asList(trailingTextHtmlArray));
+ }
+
+/**
+ FoodServicesCard c1;
+ FoodServicesCard c2;
+ FoodServicesCard c3;
+
+ @BeforeEach
+ void runBefore() {
+ c1 = new FoodServicesCard(0);
+ c2 = new FoodServicesCard(100);
+ c3 = new FoodServicesCard(2000);
+ }
+
+ @Test
+ void testReloadingAndPurchasing() {
+ assertFalse(c1.makePurchase(100));
+ assertEquals(c1.getBalance(), 0);
+ c2.reload(10);
+ assertEquals(c2.getBalance(), 110);
+ assertTrue(c3.makePurchase(1400));
+ assertEquals(c3.getBalance(), 600);
+ }
+
+ @Test
+ void testRewardPoints() {
+ if (c1.makePurchase(c1.POINTS_NEEDED_FOR_CASH_BACK / 2)) {
+ assertEquals(c1.getRewardPoints(), (c1.POINTS_NEEDED_FOR_CASH_BACK / 2));
+ } else {
+ assertEquals(c1.getRewardPoints(), 0);
+ }
+ c2.makePurchase(c2.POINTS_NEEDED_FOR_CASH_BACK);
+ assertEquals(c2.getRewardPoints(), 0);
+ c3.makePurchase(1200);
+ assertEquals(c3.getRewardPoints(), 1200 % c3.POINTS_NEEDED_FOR_CASH_BACK);
+ }
+ */
+} \ No newline at end of file
diff --git a/src/test/model/MyModelTest.java b/src/test/model/MyModelTest.java
deleted file mode 100644
index c41f32e..0000000
--- a/src/test/model/MyModelTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class MyModelTest {
- // delete or rename this class!
-} \ No newline at end of file