소스 검색

Add formatters for Duration and Amount in anticipation of using them.

Sam Jaffe 5 년 전
부모
커밋
bae1361be4

+ 34 - 0
src/main/lombok/org/leumasjaffe/recipe/view/formatter/AmountFormatter.java

@@ -0,0 +1,34 @@
+package org.leumasjaffe.recipe.view.formatter;
+
+import java.text.ParseException;
+
+import javax.swing.text.DefaultFormatter;
+
+import org.leumasjaffe.recipe.model.Amount;
+
+public class AmountFormatter extends DefaultFormatter {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7379502839670512936L;
+	
+	public AmountFormatter() {
+		setCommitsOnValidEdit(false);
+	}
+
+	@Override
+	public Amount stringToValue(String text) throws ParseException {
+		final int to = text.indexOf(' ');
+		try {
+			Float.parseFloat(to == -1 ? text : text.substring(0, to));
+		} catch (NumberFormatException nfe) {
+			throw new ParseException(nfe.getMessage(), 0);
+		}
+
+		// This is technically a little permissive, since we're not checking
+		// the validity of the unit type.
+		return new Amount(text);
+	}
+
+}

+ 49 - 0
src/main/lombok/org/leumasjaffe/recipe/view/formatter/DurationFormatter.java

@@ -0,0 +1,49 @@
+package org.leumasjaffe.recipe.view.formatter;
+
+import java.text.ParseException;
+
+import javax.swing.text.DefaultFormatter;
+
+import org.leumasjaffe.recipe.model.Duration;
+
+public class DurationFormatter extends DefaultFormatter {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -2233461250996247706L;
+	
+	public DurationFormatter() {
+		setCommitsOnValidEdit(false);
+	}
+
+	@Override
+	public Duration stringToValue(String text) throws ParseException {
+		int tokens = 0;
+		int from = 0;
+		for (int to = text.indexOf(' '); to != -1;
+				from = to + 1, to = text.indexOf(' ', from), ++tokens) {
+			// In order to pass muster - a string must match the following:
+			// Composed of either 2 or 4 tokens (space separated) matching the regex:
+			// (\d+(\.5)? - )?\d+(\.5)? (s|min|hr)
+			if (tokens == 1) { continue; } // Ignore '-'
+			else if (tokens == 3) {
+				throw new ParseException("Too many tokens in input", from);
+			}
+			try {
+				Float.parseFloat(text.substring(from, to));
+			} catch (NumberFormatException nfe) {
+				throw new ParseException(nfe.getMessage(), from);
+			}
+		}
+		
+		// Less efficient, but this allows me to punt the validation to the object
+		// once I'm confident it 'appears' correct.
+		try {
+			return new Duration(text);
+		} catch (IllegalArgumentException | ArrayIndexOutOfBoundsException ex) {
+			throw new ParseException("No valid duration interval was provided", from);
+		}
+	}
+
+}

+ 40 - 0
src/test/java/org/leumasjaffe/recipe/view/formatter/AmountFormatterTest.java

@@ -0,0 +1,40 @@
+package org.leumasjaffe.recipe.view.formatter;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.text.ParseException;
+
+import org.junit.jupiter.api.Test;
+
+class AmountFormatterTest {
+	
+	AmountFormatter formatter = new AmountFormatter();
+
+	@Test
+	void testCanParseValidStrings() {
+		assertDoesNotThrow(() -> formatter.stringToValue("1"));
+		assertDoesNotThrow(() -> formatter.stringToValue("1 ct"));
+		assertDoesNotThrow(() -> formatter.stringToValue("1 g"));
+		assertDoesNotThrow(() -> formatter.stringToValue("1 tsp"));
+	}
+	
+	@Test
+	void testCanParseRandomNames() {
+		assertDoesNotThrow(() -> formatter.stringToValue("1 large"));
+		assertDoesNotThrow(() -> formatter.stringToValue("1 bacon pancake"));
+	}
+
+
+	@Test
+	void testThrowsErrorOnInvalidFloat() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0.Q"));
+	}
+
+	@Test
+	void testThrowsErrorEmptyString() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue(""));
+	}
+
+}

+ 56 - 0
src/test/java/org/leumasjaffe/recipe/view/formatter/DurationFormatterTest.java

@@ -0,0 +1,56 @@
+package org.leumasjaffe.recipe.view.formatter;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.text.ParseException;
+
+import org.junit.jupiter.api.Test;
+
+class DurationFormatterTest {
+	
+	DurationFormatter formatter = new DurationFormatter();
+
+	@Test
+	void testCanParseValidStrings() {
+		assertDoesNotThrow(() -> formatter.stringToValue("10 s"));
+		assertDoesNotThrow(() -> formatter.stringToValue("10 - 20 s"));
+	}
+	
+	@Test
+	void testThrowsErrorOnUnknownEnum() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("10 tocks"));
+	}
+
+	@Test
+	void testThrowsErrorOnInvalidFloat() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0.Q s"));
+	}
+
+	@Test
+	void testThrowsErrorEmptyString() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue(""));
+	}
+	
+	@Test
+	void testThrowsErrorOneArg() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0"));
+	}
+
+	@Test
+	void testThrowsErrorThreeArgs() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0 - s"));
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0 1 s"));
+	}
+
+	@Test
+	void testThrowsErrorMoreThanFourArgs() {
+		assertThrows(ParseException.class,
+				() -> formatter.stringToValue("0 - 1 s s"));
+	}
+}