diff --git a/pom.xml b/pom.xml index 0ba4cd48..77de9bed 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.quickwrite fluent4j - 0.2.0-alpha + 0.2.1-alpha diff --git a/src/main/java/net/quickwrite/fluent4j/ast/FluentBase.java b/src/main/java/net/quickwrite/fluent4j/ast/FluentBase.java index 57554c4a..d12ac430 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/FluentBase.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/FluentBase.java @@ -1,21 +1,11 @@ package net.quickwrite.fluent4j.ast; -import net.quickwrite.fluent4j.ast.placeable.AttributeReference; -import net.quickwrite.fluent4j.ast.placeable.SelectExpression; -import net.quickwrite.fluent4j.ast.placeable.TermReference; -import net.quickwrite.fluent4j.ast.placeable.base.FluentPlaceable; -import net.quickwrite.fluent4j.ast.placeable.base.FluentSelectable; import net.quickwrite.fluent4j.exception.FluentParseException; -import net.quickwrite.fluent4j.exception.FluentSelectException; -import net.quickwrite.fluent4j.parser.FluentParser; import net.quickwrite.fluent4j.util.StringSlice; import net.quickwrite.fluent4j.util.StringSliceUtil; import net.quickwrite.fluent4j.util.args.FluentArgs; import net.quickwrite.fluent4j.util.bundle.DirectFluentBundle; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -51,11 +41,17 @@ private List parse(final StringSlice content) { while (!content.isBigger()) { if (content.getChar() == '{') { - elements.add(getPlaceable(content)); + content.increment(); + elements.add(StringSliceUtil.getPlaceable(content)); + + if (content.getChar() != '}') { + throw new FluentParseException('}', content.getCharUTF16(), content.getAbsolutePosition()); + } + content.increment(); } else { FluentTextElement text = getText(content, firstLine); - if (text != null) { + if (text != null && !text.isEmpty()) { elements.add(text); } } @@ -88,107 +84,10 @@ private FluentTextElement getText(final StringSlice content, final boolean first return new FluentTextElement(content.substring(start, content.getPosition()), whitespace); } - private FluentPlaceable getPlaceable(final StringSlice content) { - content.increment(); - StringSliceUtil.skipWhitespaceAndNL(content); - - FluentPlaceable placeable = StringSliceUtil.getExpression(content); - - boolean canSelect = placeable instanceof FluentSelectable; - - StringSliceUtil.skipWhitespaceAndNL(content); - - if (canSelect && content.getChar() == '-') { - content.increment(); - if (content.getChar() != '>') { - throw new FluentParseException("->", "-" + content.getCharUTF16(), content.getAbsolutePosition()); - } - - content.increment(); - - StringSliceUtil.skipWhitespaceAndNL(content); - - List fluentVariants = new ArrayList<>(); - FluentVariant defaultVariant = null; - - while (content.getChar() != '}') { - Pair variant = getVariant(content); - - fluentVariants.add(variant.getLeft()); - - if (!variant.getRight()) { - continue; - } - - if (defaultVariant != null) { - throw new FluentSelectException("Only one variant can be marked as default (*)"); - } - - defaultVariant = variant.getLeft(); - } - - if (defaultVariant == null) { - throw new FluentSelectException("Expected one of the variants to be marked as default (*)"); - } - - placeable = new SelectExpression(placeable, fluentVariants, defaultVariant); - } - - StringSliceUtil.skipWhitespaceAndNL(content); - - if (content.getChar() != '}') { - throw new FluentParseException('}', content.getCharUTF16(), content.getAbsolutePosition()); - } - - content.increment(); - - return placeable; - } - public String getIdentifier() { return this.identifier; } - private Pair getVariant(final StringSlice content) { - StringSliceUtil.skipWhitespaceAndNL(content); - - boolean isDefault = false; - - if (content.getChar() == '*') { - isDefault = true; - content.increment(); - } - - if (content.getChar() != '[') { - throw new FluentParseException('[', content.getCharUTF16(), content.getAbsolutePosition()); - } - - content.increment(); - - StringSliceUtil.skipWhitespace(content); - - StringSlice identifier = getVariantIdentifier(content); - - StringSliceUtil.skipWhitespace(content); - - if (content.getChar() != ']') { - throw getVariantException(content, identifier.toString(), "]"); - } - - content.increment(); - - final Pair stringSliceContent = FluentParser.getMessageContent(content, - character -> character == '[' || character == '*' || character == '}'); - - final FluentAttribute attribute = new FluentAttribute( - identifier, - stringSliceContent.getLeft(), - stringSliceContent.getRight() - ); - - return new ImmutablePair<>(new FluentVariant(attribute), isDefault); - } - private StringSlice getVariantIdentifier(final StringSlice content) { char character = content.getChar(); final int start = content.getPosition(); @@ -238,16 +137,4 @@ public String stringValue() { public List getElements() { return this.fluentElements; } - - private FluentParseException getVariantException(final StringSlice content, final String prev, final String expected) { - int start = content.getPosition(); - - while (content.getChar() != ']' && !content.isBigger()) { - content.increment(); - } - - return new FluentParseException(expected, - prev + content.substring(start, content.getPosition()).toString(), - content.getAbsolutePosition()); - } } diff --git a/src/main/java/net/quickwrite/fluent4j/ast/FluentTextElement.java b/src/main/java/net/quickwrite/fluent4j/ast/FluentTextElement.java index 025df9f2..6fcae2f0 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/FluentTextElement.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/FluentTextElement.java @@ -67,6 +67,10 @@ private String getText(final StringSlice content, final int whitespace) { return text.toString(); } + public boolean isEmpty() { + return text.isEmpty(); + } + @Override public boolean matches(final DirectFluentBundle bundle, final FluentElement selector) { return selector.stringValue().equals(this.text); diff --git a/src/main/java/net/quickwrite/fluent4j/ast/FluentVariant.java b/src/main/java/net/quickwrite/fluent4j/ast/FluentVariant.java index a3873e0d..be73cabe 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/FluentVariant.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/FluentVariant.java @@ -1,5 +1,6 @@ package net.quickwrite.fluent4j.ast; +import net.quickwrite.fluent4j.exception.FluentParseException; import net.quickwrite.fluent4j.util.args.FluentArgs; import net.quickwrite.fluent4j.util.bundle.DirectFluentBundle; import net.quickwrite.fluent4j.ast.placeable.NumberLiteral; @@ -21,14 +22,18 @@ public class FluentVariant implements FluentElement { private final FluentPlaceable identifier; private final FluentAttribute content; - public FluentVariant(FluentAttribute content) { + public FluentVariant(final FluentAttribute content) { this.identifier = getIdentifier(content.identifier); this.content = content; } - private FluentPlaceable getIdentifier(String slice) { + private FluentPlaceable getIdentifier(final String slice) { if (Character.isDigit(slice.charAt(0))) { - return NumberLiteral.getNumberLiteral(slice); + try { + return NumberLiteral.getNumberLiteral(slice); + } catch (final NumberFormatException ignored) { + throw new FluentParseException("Expected Number but got \"" + slice + "\""); + } } return new StringLiteral(slice); diff --git a/src/main/java/net/quickwrite/fluent4j/ast/placeable/AttributeReference.java b/src/main/java/net/quickwrite/fluent4j/ast/placeable/AttributeReference.java index a44b361d..4652fbfb 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/placeable/AttributeReference.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/placeable/AttributeReference.java @@ -53,14 +53,19 @@ public CharSequence getResult(final DirectFluentBundle bundle, final FluentArgs return getErrorString(); } - return attribute.getResult(bundle, arguments); + return attribute.getResult(bundle, getArguments(arguments)); } @Override public FluentElement getArgumentResult(final DirectFluentBundle bundle, final FluentArgs arguments) { - final FluentAttribute attribute = this.getMessage(bundle, reference.stringValue()) - .getAttribute(this.attributeIdentifier); - if (attribute == null) { + final FluentMessage fluentMessage = this.getMessage(bundle, reference.stringValue()); + if (fluentMessage == null) { + return this; + } + + final FluentAttribute attribute = fluentMessage.getAttribute(this.attributeIdentifier); + + if(attribute == null) { return this; } @@ -71,7 +76,7 @@ public FluentElement getArgumentResult(final DirectFluentBundle bundle, final Fl } // No recursion (unfortunately :d) - return (FluentElement) elementList.get(0); + return elementList.get(0); } protected FluentMessage getMessage(final DirectFluentBundle bundle, final String key) { @@ -82,6 +87,10 @@ protected String getErrorString() { return "{" + reference.stringValue() + "." + attributeIdentifier + "}"; } + protected FluentArgs getArguments(final FluentArgs defaultArgs) { + return defaultArgs; + } + @Override public String toString() { return "FluentAttributeReference: {\n" + @@ -91,8 +100,12 @@ public String toString() { } public static class TermAttributeReference extends AttributeReference implements FluentSelectable { - public TermAttributeReference(FluentPlaceable reference, StringSlice content) { + private final FluentArgs arguments; + + public TermAttributeReference(final FluentPlaceable reference, final StringSlice content, final FluentArgs arguments) { super(reference, content); + + this.arguments = arguments; } @Override @@ -104,5 +117,19 @@ protected FluentMessage getMessage(final DirectFluentBundle bundle, final String protected String getErrorString() { return "{-" + reference.stringValue() + "." + attributeIdentifier + "}"; } + + @Override + protected FluentArgs getArguments(final FluentArgs defaultArgs) { + return this.arguments; + } + + @Override + public String toString() { + return "FluentTermAttributeReference: {\n" + + "\t\t\tvalue: \"" + this.reference + "\"\n" + + "\t\t\tattribute: \"" + this.attributeIdentifier + "\"\n" + + "\t\t\targuments: \"" + this.arguments + "\"\n" + + "\t\t}"; + } } } \ No newline at end of file diff --git a/src/main/java/net/quickwrite/fluent4j/ast/placeable/FunctionReference.java b/src/main/java/net/quickwrite/fluent4j/ast/placeable/FunctionReference.java index a42d4ba7..425b067d 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/placeable/FunctionReference.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/placeable/FunctionReference.java @@ -16,8 +16,8 @@ */ public class FunctionReference extends FluentFunction implements FluentSelectable { - public FunctionReference(final String functionName, final StringSlice content) { - super(functionName, content); + public FunctionReference(final String functionName, final FluentArgs arguments) { + super(functionName, arguments); } @Override diff --git a/src/main/java/net/quickwrite/fluent4j/ast/placeable/TermReference.java b/src/main/java/net/quickwrite/fluent4j/ast/placeable/TermReference.java index ec34c9f9..d3cad0c5 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/placeable/TermReference.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/placeable/TermReference.java @@ -5,7 +5,6 @@ import net.quickwrite.fluent4j.ast.placeable.base.FluentFunction; import net.quickwrite.fluent4j.util.StringSlice; import net.quickwrite.fluent4j.util.args.FluentArgs; -import net.quickwrite.fluent4j.util.args.FluentArguments; import net.quickwrite.fluent4j.util.bundle.DirectFluentBundle; /** @@ -30,8 +29,8 @@ public TermReference(final StringSlice name) { super(name, null); } - public TermReference(final String name, final StringSlice content) { - super(name, content); + public TermReference(final String name, final FluentArgs arguments) { + super(name, arguments); } @Override @@ -60,11 +59,6 @@ public FluentElement getArgumentResult(final DirectFluentBundle bundle, final Fl return term; } - @Override - protected FluentArgs getFluentArgumentInstance() { - return new FluentArguments(); - } - @Override public String toString() { return "FluentTermReference: {\n" + diff --git a/src/main/java/net/quickwrite/fluent4j/ast/placeable/base/FluentFunction.java b/src/main/java/net/quickwrite/fluent4j/ast/placeable/base/FluentFunction.java index 056f3789..9b1b15c9 100644 --- a/src/main/java/net/quickwrite/fluent4j/ast/placeable/base/FluentFunction.java +++ b/src/main/java/net/quickwrite/fluent4j/ast/placeable/base/FluentFunction.java @@ -3,13 +3,9 @@ import net.quickwrite.fluent4j.ast.FluentElement; import net.quickwrite.fluent4j.exception.FluentParseException; import net.quickwrite.fluent4j.util.StringSlice; -import net.quickwrite.fluent4j.util.StringSliceUtil; import net.quickwrite.fluent4j.util.args.FluentArgs; -import net.quickwrite.fluent4j.util.args.FunctionFluentArgs; import net.quickwrite.fluent4j.util.args.FunctionFluentArguments; import net.quickwrite.fluent4j.util.bundle.DirectFluentBundle; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; /** * Implements the basis for a value that gets @@ -20,68 +16,18 @@ public abstract class FluentFunction implements FluentPlaceable, FluentArgumentR protected final String functionName; protected final FluentArgs arguments; - public FluentFunction(final StringSlice functionName, final StringSlice content) { - this(functionName.toString(), content); + public FluentFunction(final StringSlice functionName, final FluentArgs arguments) { + this(functionName.toString(), arguments); } - public FluentFunction(final String functionName, final StringSlice content) { + public FluentFunction(final String functionName, final FluentArgs arguments) { this.functionName = functionName; if (!check(functionName)) { // TODO: Better Error handling throw new FluentParseException("The callee has to be an upper-case identifier or a term"); } - this.arguments = (content == null) ? FunctionFluentArgs.EMPTY_ARGS : this.getArguments(content); - } - - private FluentArgs getArguments(final StringSlice content) { - StringSliceUtil.skipWhitespaceAndNL(content); - if (content.isBigger()) { - return FunctionFluentArgs.EMPTY_ARGS; - } - - final FunctionFluentArgs arguments = (FunctionFluentArgs) this.getFluentArgumentInstance(); - - while (!content.isBigger()) { - Pair argument = getArgument(content); - if (argument.getLeft() != null) { - arguments.setNamed(argument.getLeft(), argument.getRight()); - } else { - arguments.addPositional(argument.getRight()); - } - - StringSliceUtil.skipWhitespaceAndNL(content); - - if (content.getChar() != ',') { - if (!content.isBigger()) { - throw new FluentParseException("','", content.getCharUTF16(), content.getAbsolutePosition()); - } - break; - } - content.increment(); - - StringSliceUtil.skipWhitespaceAndNL(content); - } - - return arguments; - } - - private Pair getArgument(final StringSlice content) { - FluentPlaceable placeable = StringSliceUtil.getExpression(content); - String identifier = null; - - StringSliceUtil.skipWhitespaceAndNL(content); - - if (content.getChar() == ':') { - content.increment(); - StringSliceUtil.skipWhitespaceAndNL(content); - - identifier = placeable.stringValue(); - - placeable = StringSliceUtil.getExpression(content); - } - - return new ImmutablePair<>(identifier, placeable); + this.arguments = arguments != null ? arguments : FluentArgs.EMPTY_ARGS; } /** @@ -93,12 +39,10 @@ private Pair getArgument(final StringSlice content) { * @return The sanitized arguments of the function */ protected FluentArgs getArguments(final DirectFluentBundle bundle, final FluentArgs arguments) { - this.arguments.sanitize(bundle, arguments); - return this.arguments; - } + if (this.arguments != null) + this.arguments.sanitize(bundle, arguments); - protected FluentArgs getFluentArgumentInstance() { - return new FunctionFluentArguments(); + return this.arguments; } /** diff --git a/src/main/java/net/quickwrite/fluent4j/parser/FluentParser.java b/src/main/java/net/quickwrite/fluent4j/parser/FluentParser.java index 6c6900bd..5e8f717d 100644 --- a/src/main/java/net/quickwrite/fluent4j/parser/FluentParser.java +++ b/src/main/java/net/quickwrite/fluent4j/parser/FluentParser.java @@ -1,17 +1,18 @@ package net.quickwrite.fluent4j.parser; -import net.quickwrite.fluent4j.util.bundle.FluentResource; -import net.quickwrite.fluent4j.util.bundle.SimpleFluentResource; import net.quickwrite.fluent4j.ast.*; import net.quickwrite.fluent4j.exception.FluentParseException; import net.quickwrite.fluent4j.util.StringSlice; import net.quickwrite.fluent4j.util.StringSliceUtil; +import net.quickwrite.fluent4j.util.bundle.FluentResource; +import net.quickwrite.fluent4j.util.bundle.SimpleFluentResource; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.regex.Pattern; /** * Parses a String into a FluentResource so that it can be queried. @@ -30,20 +31,20 @@ public abstract class FluentParser { * * @return FluentResource */ - public static FluentResource parse(final String content) { - final StringSlice input = convertString(content); + public static FluentResource parse(final String input) { + final StringSlice content = convertString(input); List elementList = new ArrayList<>(); List exceptionList = new LinkedList<>(); - while (input.length() >= input.length()) { - if (input.getChar() == '#') { - handleComment(input); + while (content.length() >= content.length()) { + if (content.getChar() == '#') { + handleComment(content); continue; } try { - FluentBase fluentBase = getBase(input); + FluentBase fluentBase = getBase(content); if (fluentBase != null) { elementList.add(fluentBase); @@ -54,48 +55,48 @@ public static FluentResource parse(final String content) { continue; } - int startSkip = input.getPosition(); - StringSliceUtil.skipWhitespaceAndNL(input); + int startSkip = content.getPosition(); + StringSliceUtil.skipWhitespaceAndNL(content); - if (startSkip == input.getPosition()) { - if (input.getChar() == '\n' || input.getChar() == ' ' || input.getChar() == '\0') { + if (startSkip == content.getPosition()) { + if (content.getChar() == '\n' || content.getChar() == ' ' || content.getChar() == '\0') { break; } - exceptionList.add(new FluentParseException("an entry start", input.getCharUTF16(), input.getPosition())); + exceptionList.add(new FluentParseException("an entry start", content.getCharUTF16(), content.getPosition())); - while (input.getChar() != '\n' && !input.isBigger()) { - input.increment(); + while (content.getChar() != '\n' && !content.isBigger()) { + content.increment(); } } } - input.setIndex(0); + content.setIndex(0); return new SimpleFluentResource(elementList, exceptionList); } - private static FluentBase getBase(final StringSlice input) { + private static FluentBase getBase(final StringSlice content) { boolean isIdentifier = false; - if (input.getChar() == '-') { - input.increment(); + if (content.getChar() == '-') { + content.increment(); isIdentifier = true; - } else if (!Character.isAlphabetic(input.getChar())) { + } else if (!Character.isAlphabetic(content.getChar())) { return null; } - StringSlice identifier = StringSliceUtil.getIdentifier(input); + StringSlice identifier = StringSliceUtil.getIdentifier(content); - StringSliceUtil.skipWhitespace(input); + StringSliceUtil.skipWhitespace(content); - if (input.getChar() != '=') { - throw new FluentParseException('=', input.getCharUTF16(), input.getAbsolutePosition()); + if (content.getChar() != '=') { + throw new FluentParseException('=', content.getCharUTF16(), content.getAbsolutePosition()); } - input.increment(); + content.increment(); - final Pair, List> pair = getContent(input); + final Pair, List> pair = getContent(content); if (!isIdentifier) { // must be a Message @@ -106,9 +107,9 @@ private static FluentBase getBase(final StringSlice input) { } } - private static void handleComment(final StringSlice input) { - while (input.getChar() != '\n' && input.getChar() != '\0') { - input.increment(); + private static void handleComment(final StringSlice content) { + while (content.getChar() != '\n' && content.getChar() != '\0') { + content.increment(); } } @@ -136,98 +137,59 @@ private static Pair, List> getConten return new ImmutablePair<>(content, attributes); } - private static Pair getMessageContent(final StringSlice input) { - return getMessageContent(input, character -> character == '.'); + private static Pair getMessageContent(final StringSlice content) { + return getMessageContent(content, character -> character == '.'); } - public static Pair getMessageContent(final StringSlice input, final BreakChecker breaker) { - StringSliceUtil.skipWhitespace(input); - final int start = input.getPosition(); + public static Pair getMessageContent(final StringSlice content, final BreakChecker breaker) { + StringSliceUtil.skipWhitespace(content); + final int start = content.getPosition(); int lastWhitespace = start; boolean first = true; int leadingWhitespace = Integer.MAX_VALUE; do { - int whitespace = StringSliceUtil.skipWhitespace(input); - if (!first && whitespace < leadingWhitespace && whitespace != 0) { - leadingWhitespace = whitespace; + int whitespace = StringSliceUtil.skipWhitespace(content); + if (!first && breaker.isEndCharacter(content.getChar())) { + break; } - if (!first && breaker.isEndCharacter(input.getChar())) { - break; + if (!first && whitespace < leadingWhitespace && whitespace != 0) { + leadingWhitespace = whitespace; } first = false; - while (input.getChar() != '\n' && input.getChar() != '\0') { - if (input.getChar() == '{') { - skipPlaceable(input); + while (content.getChar() != '\n' && content.getChar() != '\0') { + if (content.getChar() == '{') { + content.increment(); + StringSliceUtil.getPlaceable(content); } - if (input.getChar() != ' ') { - lastWhitespace = input.getPosition(); + if (content.getChar() != ' ') { + lastWhitespace = content.getPosition(); } - input.increment(); + content.increment(); } - input.increment(); - } while (input.getChar() == ' ' || input.getChar() == '\n'); + content.increment(); + } while (content.getChar() == ' ' || content.getChar() == '\n'); if (leadingWhitespace == Integer.MAX_VALUE) { leadingWhitespace = 0; } - return new ImmutablePair<>(input.substring(start, lastWhitespace + 1), leadingWhitespace); + return new ImmutablePair<>(content.substring(start, lastWhitespace + 1), leadingWhitespace); } - private static void skipPlaceable(final StringSlice input) { - input.increment(); - - int openCurly = 1; - boolean justWhitespace = true; - - while (!input.isBigger()) { - char character = input.getChar(); + private final static Pattern stringConverter; - switch (character) { - case '"': - if (!justWhitespace) break; - - character = input.getChar(); - input.increment(); - - while (!(input.getChar() == '"' && character != '\\') && input.getChar() != '\n' && !input.isBigger()) { - character = input.getChar(); - input.increment(); - } - - break; - case '{': - openCurly++; - - justWhitespace = true; - - break; - case '}': - openCurly--; - - if (openCurly == 0) { - return; - } - - break; - default: - if (!Character.isWhitespace(character)) { - justWhitespace = false; - } - } - - input.increment(); - } + static { + stringConverter = Pattern.compile("(\\r\\n|\\r|\\f)"); } private static StringSlice convertString(final String input) { - return new StringSlice(input.replace("\r", "")); + return new StringSlice(stringConverter.matcher(input).replaceAll("\n")); } /** diff --git a/src/main/java/net/quickwrite/fluent4j/util/StringSliceUtil.java b/src/main/java/net/quickwrite/fluent4j/util/StringSliceUtil.java index dbb49274..11f1b674 100644 --- a/src/main/java/net/quickwrite/fluent4j/util/StringSliceUtil.java +++ b/src/main/java/net/quickwrite/fluent4j/util/StringSliceUtil.java @@ -1,8 +1,22 @@ package net.quickwrite.fluent4j.util; +import net.quickwrite.fluent4j.ast.FluentAttribute; +import net.quickwrite.fluent4j.ast.FluentElement; +import net.quickwrite.fluent4j.ast.FluentVariant; import net.quickwrite.fluent4j.ast.placeable.*; import net.quickwrite.fluent4j.ast.placeable.base.FluentPlaceable; +import net.quickwrite.fluent4j.ast.placeable.base.FluentSelectable; import net.quickwrite.fluent4j.exception.FluentParseException; +import net.quickwrite.fluent4j.exception.FluentSelectException; +import net.quickwrite.fluent4j.parser.FluentParser; +import net.quickwrite.fluent4j.util.args.FluentArgs; +import net.quickwrite.fluent4j.util.args.FunctionFluentArgs; +import net.quickwrite.fluent4j.util.args.FunctionFluentArguments; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.List; /** * A collection of different utility methods @@ -120,12 +134,7 @@ public static FluentPlaceable getExpression(final StringSlice slice) { case '"' -> { slice.increment(); final int start = slice.getPosition(); - while (!(slice.getChar() == '"' || slice.getChar() == '\n') && !slice.isBigger()) { - if (slice.getChar() == '\\' && slice.peek(1) == '"') - slice.increment(); - - slice.increment(); - } + skipStringLiteral(slice); if (slice.getChar() != '"') { slice.decrement(2); @@ -147,6 +156,16 @@ public static FluentPlaceable getExpression(final StringSlice slice) { return expression; } + public static void skipStringLiteral(final StringSlice slice) { + while (!(slice.getChar() == '"' || slice.getChar() == '\n') && !slice.isBigger()) { + final char peek = slice.peek(1); + if (slice.getChar() == '\\' && (peek == '"' || peek == '\\')) + slice.increment(); + + slice.increment(); + } + } + private static FluentPlaceable expressionGetDefault(final StringSlice slice) { boolean isTerm = false; @@ -160,7 +179,12 @@ private static FluentPlaceable expressionGetDefault(final StringSlice slice) { if (isTerm) slice.decrement(); - return NumberLiteral.getNumberLiteral(getNumber(slice)); + final StringSlice number = getNumber(slice); + try { + return NumberLiteral.getNumberLiteral(number); + } catch (final NumberFormatException ignored) { + throw new FluentParseException("Number", number.toString(), number.getPosition() - number.length()); + } } final StringSlice msgIdentifier = getIdentifier(slice); @@ -180,34 +204,14 @@ private static FluentPlaceable expressionGetDefault(final StringSlice slice) { private static FluentPlaceable expressionGetFunction(final StringSlice slice, FluentPlaceable expression, final boolean isTerm) { slice.increment(); - int start = slice.getPosition(); - - int open = 0; - - while (!(slice.getChar() == ')' && open == 0)) { - if (slice.isBigger()) { - throw new FluentParseException(")", "EOF", slice.getAbsolutePosition()); - } - - if (slice.getChar() == '(') { - open++; - } - - if (slice.getChar() == ')') { - open--; - } - - slice.increment(); - } - expression = (!isTerm) ? new FunctionReference( expression.stringValue(), - slice.substring(start, slice.getPosition()) + parseArguments(slice) ) : new TermReference( expression.stringValue(), - slice.substring(start, slice.getPosition()) + parseArguments(slice) ); slice.increment(); @@ -220,7 +224,15 @@ private static FluentPlaceable expressionGetAttribute(final StringSlice slice, F final StringSlice identifier = StringSliceUtil.getIdentifier(slice); if (isTerm) { - expression = new AttributeReference.TermAttributeReference(expression, identifier); + skipWhitespaceAndNL(slice); + FluentArgs arguments = null; + + if (slice.getChar() == '(') { + slice.increment(); + arguments = parseArguments(slice); + slice.increment(); + } + expression = new AttributeReference.TermAttributeReference(expression, identifier, arguments); } else { expression = new AttributeReference(expression, identifier); } @@ -228,6 +240,102 @@ private static FluentPlaceable expressionGetAttribute(final StringSlice slice, F return expression; } + /** + * Returns a simple {@link FluentArgs} object that + * contains the arguments that can be created in the + * {@code .ftl}-files. + * + *

+ * The arguments are always in a format + * of being in {@code ()} and being separated + * by {@code ,}. + *

+ *

+ * There are two different types of arguments: + *

    + *
  • + * Positional Arguments: + *
    + * Arguments that don't have a name and + * are just denominated by their position in the + * arguments. + *
  • + *
  • + * Named Arguments: + *
    + * Arguments that have a name that is being + * declared in front of the argument by + * having a {@code :} as a separator. + *
    + * This means that to create a named argument + * the argument is created by having this format: + * {{name}} : {{argument}} + *
    + * They can only be accessed by their name as + * the key. + *
  • + *
+ *

+ *

+ * If there are no arguments in the brackets + * the function will return {@link FluentArgs#EMPTY_ARGS}. + *

+ * + * @param content The content the arguments are in + * @return The arguments as an option + */ + private static FluentArgs parseArguments(final StringSlice content) { + if (content == null) { + return FluentArgs.EMPTY_ARGS; + } + + StringSliceUtil.skipWhitespaceAndNL(content); + if (content.isBigger()) { + return FunctionFluentArgs.EMPTY_ARGS; + } + + final FunctionFluentArgs arguments = new FunctionFluentArguments(); + + while (!content.isBigger() && content.getChar() != ')') { + Pair argument = getArgument(content); + + if (argument.getLeft() != null) { + arguments.setNamed(argument.getLeft(), argument.getRight()); + } else { + arguments.addPositional(argument.getRight()); + } + + StringSliceUtil.skipWhitespaceAndNL(content); + + if (content.getChar() != ',') { + break; + } + content.increment(); + + StringSliceUtil.skipWhitespaceAndNL(content); + } + + return arguments; + } + + private static Pair getArgument(final StringSlice content) { + FluentPlaceable placeable = StringSliceUtil.getExpression(content); + String identifier = null; + + StringSliceUtil.skipWhitespaceAndNL(content); + + if (content.getChar() == ':') { + content.increment(); + StringSliceUtil.skipWhitespaceAndNL(content); + + identifier = placeable.stringValue(); + + placeable = StringSliceUtil.getExpression(content); + } + + return new ImmutablePair<>(identifier, placeable); + } + private static StringSlice getNumber(final StringSlice slice) { char character = slice.getChar(); final int start = slice.getPosition(); @@ -271,4 +379,134 @@ public static StringSlice getIdentifier(final StringSlice slice) { return slice.substring(start, slice.getPosition()); } + + /** + * Returns the parsed version of the {@link FluentPlaceable} + * that is inside the {}. + * + *

+ * This can either be a simple expression or + * a complete {@link SelectExpression}. + *

+ * + * @param content The content that the placeable currently is at + * @return The Placeable + */ + public static FluentPlaceable getPlaceable(final StringSlice content) { + StringSliceUtil.skipWhitespaceAndNL(content); + + FluentPlaceable placeable = StringSliceUtil.getExpression(content); + + boolean canSelect = placeable instanceof FluentSelectable; + + StringSliceUtil.skipWhitespaceAndNL(content); + + if (canSelect && content.getChar() == '-') { + content.increment(); + if (content.getChar() != '>') { + throw new FluentParseException("->", "-" + content.getCharUTF16(), content.getAbsolutePosition()); + } + + content.increment(); + + StringSliceUtil.skipWhitespaceAndNL(content); + + final List fluentVariants = new ArrayList<>(); + FluentVariant defaultVariant = null; + + while (content.getChar() != '}') { + final Pair variant = getVariant(content); + + fluentVariants.add(variant.getLeft()); + + if (!variant.getRight()) { + continue; + } + + if (defaultVariant != null) { + throw new FluentSelectException("Only one variant can be marked as default (*)"); + } + + defaultVariant = variant.getLeft(); + } + + if (defaultVariant == null) { + throw new FluentSelectException("Expected one of the variants to be marked as default (*)"); + } + + placeable = new SelectExpression(placeable, fluentVariants, defaultVariant); + } + + StringSliceUtil.skipWhitespaceAndNL(content); + + return placeable; + } + + private static Pair getVariant(final StringSlice content) { + StringSliceUtil.skipWhitespaceAndNL(content); + + boolean isDefault = false; + + if (content.getChar() == '*') { + isDefault = true; + content.increment(); + } + + if (content.getChar() != '[') { + throw new FluentParseException('[', content.getCharUTF16(), content.getAbsolutePosition()); + } + + content.increment(); + + StringSliceUtil.skipWhitespace(content); + + final StringSlice identifier = getVariantIdentifier(content); + + StringSliceUtil.skipWhitespace(content); + + if (content.getChar() != ']') { + throw getVariantException(content, identifier.toString(), "]"); + } + + content.increment(); + + final Pair stringSliceContent = FluentParser.getMessageContent(content, + character -> character == '[' || character == '*' || character == '}'); + + final FluentAttribute attribute = new FluentAttribute( + identifier, + stringSliceContent.getLeft(), + stringSliceContent.getRight() + ); + + return new ImmutablePair<>(new FluentVariant(attribute), isDefault); + } + + private static StringSlice getVariantIdentifier(final StringSlice content) { + char character = content.getChar(); + final int start = content.getPosition(); + + while (character != ' ' + && character != '\n' + && character != ']' + && character != '\0' + ) { + content.increment(); + character = content.getChar(); + } + + return content.substring(start, content.getPosition()); + } + + private static FluentParseException getVariantException(final StringSlice content, final String prev, final String expected) { + int start = content.getPosition(); + + while (content.getChar() != ']' && !content.isBigger()) { + content.increment(); + } + + return new FluentParseException(expected, + prev + content.substring(start, content.getPosition()).toString(), + content.getAbsolutePosition()); + } } diff --git a/src/main/java/net/quickwrite/fluent4j/util/bundle/ResourceFluentBundle.java b/src/main/java/net/quickwrite/fluent4j/util/bundle/ResourceFluentBundle.java index 934377b0..c441530c 100644 --- a/src/main/java/net/quickwrite/fluent4j/util/bundle/ResourceFluentBundle.java +++ b/src/main/java/net/quickwrite/fluent4j/util/bundle/ResourceFluentBundle.java @@ -128,4 +128,15 @@ public boolean hasExceptions() { public List getExceptionList() { return this.exceptionList; } + + @Override + public String toString() { + return "ResourceFluentBundle: {\n" + + "\tlocale: " + this.locale + "\n" + + "\tterms: [\n\t\t" + this.terms + "\n\t]\n" + + "\tmessages: [\n\t\t" + this.messages + "\n\t]\n" + + "\tfunctions: [\n\t\t" + this.functions + "\n\t]\n" + + "\texceptions: [\n\t\t" + this.exceptionList + "\n\t]\n" + + "}"; + } } diff --git a/src/test/java/net/quickwrite/fluent4j/TestCR.java b/src/test/java/net/quickwrite/fluent4j/TestCR.java new file mode 100644 index 00000000..566211e6 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestCR.java @@ -0,0 +1,32 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestCR { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("cr.ftl"); + } + + @Test + public void testErr01() { + Assertions.assertEquals("Value 01", GetFileHelper.getMessage(bundle, "err01")); + } + + @Test + public void testErr02() { + Assertions.assertEquals("Value 02", GetFileHelper.getMessage(bundle, "err02")); + } + + @Test + public void testErr03() { + Assertions.assertEquals("Value 03\nContinued", GetFileHelper.getMessage(bundle, "err03")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestCRLF.java b/src/test/java/net/quickwrite/fluent4j/TestCRLF.java new file mode 100644 index 00000000..90bea297 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestCRLF.java @@ -0,0 +1,27 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestCRLF { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("crlf.ftl"); + } + + @Test + public void testKey01() { + Assertions.assertEquals("Value 01", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("Value 02\nContinued", GetFileHelper.getMessage(bundle, "key02")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestCallExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestCallExpressions.java index ccd25db8..31fb025c 100644 --- a/src/test/java/net/quickwrite/fluent4j/TestCallExpressions.java +++ b/src/test/java/net/quickwrite/fluent4j/TestCallExpressions.java @@ -3,7 +3,6 @@ import net.quickwrite.fluent4j.ast.placeable.StringLiteral; import net.quickwrite.fluent4j.ast.placeable.base.FluentPlaceable; import net.quickwrite.fluent4j.functions.AbstractFunction; -import net.quickwrite.fluent4j.util.args.FluentArgs; import net.quickwrite.fluent4j.util.args.FunctionFluentArgs; import net.quickwrite.fluent4j.util.bundle.DirectFluentBundle; import net.quickwrite.fluent4j.util.bundle.FluentBundle; diff --git a/src/test/java/net/quickwrite/fluent4j/TestCalleeExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestCalleeExpressions.java new file mode 100644 index 00000000..7a7fab34 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestCalleeExpressions.java @@ -0,0 +1,42 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class TestCalleeExpressions { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("callee_expressions.ftl"); + } + + @Test + public void testIfExceptions() { + Assert.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testFunctionCalleePlaceable() { + Assert.assertEquals("{FUNCTION()}", GetFileHelper.getMessage(bundle, "function-callee-placeable")); + } + + @Test + public void testTermCalleePlaceable() { + Assert.assertEquals("{-term}", GetFileHelper.getMessage(bundle, "term-callee-placeable")); + } + + @Test + public void testFunctionCalleeSelector() { + Assert.assertEquals("Value", GetFileHelper.getMessage(bundle, "function-callee-selector")); + } + + @Test + public void testTermAttrCalleeSelector() { + Assert.assertEquals("Value", GetFileHelper.getMessage(bundle, "term-attr-callee-selector")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestComments.java b/src/test/java/net/quickwrite/fluent4j/TestComments.java new file mode 100644 index 00000000..6d512441 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestComments.java @@ -0,0 +1,27 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestComments { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("comments.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testMessage() { + Assertions.assertEquals("Foo", GetFileHelper.getMessage(bundle, "foo")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFComment.java b/src/test/java/net/quickwrite/fluent4j/TestEOFComment.java new file mode 100644 index 00000000..09decf1c --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFComment.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFComment { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_comment.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFEmpty.java b/src/test/java/net/quickwrite/fluent4j/TestEOFEmpty.java new file mode 100644 index 00000000..39e0a7f3 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFEmpty.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFEmpty { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_empty.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFId.java b/src/test/java/net/quickwrite/fluent4j/TestEOFId.java new file mode 100644 index 00000000..17dd9787 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFId.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFId { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_id.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFIdEquals.java b/src/test/java/net/quickwrite/fluent4j/TestEOFIdEquals.java new file mode 100644 index 00000000..efea3fdd --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFIdEquals.java @@ -0,0 +1,27 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFIdEquals { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_id_equals.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testMessageId() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "message-id")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFJunk.java b/src/test/java/net/quickwrite/fluent4j/TestEOFJunk.java new file mode 100644 index 00000000..3ed1bd74 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFJunk.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFJunk { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_junk.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEOFValue.java b/src/test/java/net/quickwrite/fluent4j/TestEOFValue.java new file mode 100644 index 00000000..ed6d0e31 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEOFValue.java @@ -0,0 +1,27 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEOFValue { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("eof_value.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testMessageId() { + Assertions.assertEquals("No EOL", GetFileHelper.getMessage(bundle, "no-eol")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestEscapedCharacters.java b/src/test/java/net/quickwrite/fluent4j/TestEscapedCharacters.java new file mode 100644 index 00000000..2b6284e4 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestEscapedCharacters.java @@ -0,0 +1,92 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestEscapedCharacters { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("escaped_characters.ftl"); + } + + @Test + public void testTextBackslashOne() { + Assertions.assertEquals("Value with \\ a backslash", GetFileHelper.getMessage(bundle, "text-backslash-one")); + } + + @Test + public void testTextBackslashTwo() { + Assertions.assertEquals("Value with \\\\ two backslashes", GetFileHelper.getMessage(bundle, "text-backslash-two")); + } + + @Test + public void testTextBackslashBrace() { + Assertions.assertEquals("Value with \\{placeable}", GetFileHelper.getMessage(bundle, "text-backslash-brace")); + } + + @Test + public void testTextBackslashU() { + Assertions.assertEquals("\\u0041", GetFileHelper.getMessage(bundle, "text-backslash-u")); + } + + @Test + public void testTextBackslashBackslashU() { + Assertions.assertEquals("\\\\u0041", GetFileHelper.getMessage(bundle, "text-backslash-backslash-u")); + } + + @Test + public void testQuoteInString() { + Assertions.assertEquals("\"", GetFileHelper.getMessage(bundle, "quote-in-string")); + } + + @Test + public void testBackslashInString() { + Assertions.assertEquals("\\", GetFileHelper.getMessage(bundle, "backslash-in-string")); + } + + @Test + public void testStringUnicode4Digits() { + Assertions.assertEquals("\u0041", GetFileHelper.getMessage(bundle, "string-unicode-4digits")); + } + + @Test + public void testEscapeUnicode4Digits() { + Assertions.assertEquals("\\u0041", GetFileHelper.getMessage(bundle, "escape-unicode-4digits")); + } + + @Test + public void testStringUnicode6Digits() { + Assertions.assertEquals("\uD83D\uDE02", GetFileHelper.getMessage(bundle, "string-unicode-6digits")); + } + + @Test + public void testEscapeUnicode6Digits() { + Assertions.assertEquals("\\U01F602", GetFileHelper.getMessage(bundle, "escape-unicode-6digits")); + } + + @Test + public void testStringTooMany4Digits() { + Assertions.assertEquals("\u004100", GetFileHelper.getMessage(bundle, "string-too-many-4digits")); + } + + @Test + public void testStringTooMany6Digits() { + Assertions.assertEquals("\uD83D\uDE0200", GetFileHelper.getMessage(bundle, "string-too-many-6digits")); + } + + @Test + public void testLiteralBraceOpen() { + Assertions.assertEquals("An opening { brace.", GetFileHelper.getMessage(bundle, "brace-open")); + } + + @Test + public void testLiteralBraceClose() { + Assertions.assertEquals("A closing } brace.", GetFileHelper.getMessage(bundle, "brace-close")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestJunk.java b/src/test/java/net/quickwrite/fluent4j/TestJunk.java new file mode 100644 index 00000000..3754dcf7 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestJunk.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestJunk { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("junk.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestLeadingDots.java b/src/test/java/net/quickwrite/fluent4j/TestLeadingDots.java new file mode 100644 index 00000000..d3a581e2 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestLeadingDots.java @@ -0,0 +1,87 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestLeadingDots { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("leading_dots.ftl"); + } + + @Test + public void testKey01() { + Assertions.assertEquals(".Value", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("…Value", GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals(".Value", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals(".Value", GetFileHelper.getMessage(bundle, "key04")); + } + + @Test + public void testKey05() { + Assertions.assertEquals("Value\n.Continued", GetFileHelper.getMessage(bundle, "key05")); + } + + @Test + public void testKey06() { + Assertions.assertEquals(".Value\n.Continued", GetFileHelper.getMessage(bundle, "key06")); + } + + @Test + public void testKey10() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key10")); + } + + @Test + public void testKey11() { + Assertions.assertEquals(".Value = which looks like an attribute\nContinued", GetFileHelper.getMessage(bundle, "key11")); + } + + @Test + public void testKey12() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key12")); + } + + @Test + public void testKey13() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key13")); + } + + @Test + public void testKey14() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key12")); + } + + @Test + public void testKey15() { + Assertions.assertEquals(".Value", GetFileHelper.getMessage(bundle, "key15")); + } + + @Test + public void testKey16() { + Assertions.assertEquals(".Value", GetFileHelper.getMessage(bundle, "key16")); + } + + @Test + public void testKey17() { + Assertions.assertEquals("Value\n.Continued", GetFileHelper.getMessage(bundle, "key17")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestLiteralExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestLiteralExpressions.java new file mode 100644 index 00000000..6c22d52c --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestLiteralExpressions.java @@ -0,0 +1,47 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestLiteralExpressions { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("literal_expressions.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testStringExpression() { + Assertions.assertEquals("abc", GetFileHelper.getMessage(bundle, "string-expression")); + } + + @Test + public void testNumberExpression() { + Assertions.assertEquals("123", GetFileHelper.getMessage(bundle, "number-expression")); + } + + @Test + public void testNegativeNumberExpression() { + Assertions.assertEquals("-42", GetFileHelper.getMessage(bundle, "negative-number-expression")); + } + + @Test + public void testFloatExpression() { + Assertions.assertEquals("3.141", GetFileHelper.getMessage(bundle, "float-expression")); + } + + @Test + public void testNegativeFloatExpression() { + Assertions.assertEquals("-6.282", GetFileHelper.getMessage(bundle, "negative-float-expression")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestMemberExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestMemberExpressions.java new file mode 100644 index 00000000..6700a010 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestMemberExpressions.java @@ -0,0 +1,42 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestMemberExpressions { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("member_expressions.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testMessageAttributeExpressionPlaceable() { + Assertions.assertEquals("{msg.attr}", GetFileHelper.getMessage(bundle, "message-attribute-expression-placeable")); + } + + @Test + public void testTermAttributeExpressionPlaceable() { + Assertions.assertEquals("{-term.attr}", GetFileHelper.getMessage(bundle, "term-attribute-expression-placeable")); + } + + @Test + public void testTermAttributeExpressionSelector() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "term-attribute-expression-selector")); + } + + @Test + public void testMessageAttributeExpressionSelector() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "message-attribute-expression-selector")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestMessages.java b/src/test/java/net/quickwrite/fluent4j/TestMessages.java new file mode 100644 index 00000000..37673af0 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestMessages.java @@ -0,0 +1,87 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestMessages { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("messages.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("Value2", GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key04")); + } + + @Test + public void testKey05() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key05")); + } + + @Test + public void testNoWhitespace() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "no-whitespace")); + } + + @Test + public void testExtraWhitespace() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "extra-whitespace")); + } + + @Test + public void testKey06() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key06")); + } + + @Test + public void testKey09() { + Assertions.assertEquals("Value 09", GetFileHelper.getMessage(bundle, "KEY09")); + } + + @Test + public void testKey10() { + Assertions.assertEquals("Value 10", GetFileHelper.getMessage(bundle, "key-10")); + } + + @Test + public void testKey11() { + Assertions.assertEquals("Value 11", GetFileHelper.getMessage(bundle, "key_11")); + } + + @Test + public void testKey12() { + Assertions.assertEquals("Value 12", GetFileHelper.getMessage(bundle, "key-12-")); + } + + @Test + public void testKey13() { + Assertions.assertEquals("Value 13", GetFileHelper.getMessage(bundle, "key_13_")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestMixedEntries.java b/src/test/java/net/quickwrite/fluent4j/TestMixedEntries.java new file mode 100644 index 00000000..2a6e1b39 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestMixedEntries.java @@ -0,0 +1,52 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestMixedEntries { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("mixed_entries.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testNonASCIICharacter1() { + Assertions.assertEquals("Custom Identifier", GetFileHelper.getMessage(bundle, "ą")); + } + + @Test + public void testNonASCIICharacter2() { + Assertions.assertEquals("Another one", GetFileHelper.getMessage(bundle, "ć")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals("Value 03", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals("Value 04", GetFileHelper.getMessage(bundle, "key04")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestMultilineValues.java b/src/test/java/net/quickwrite/fluent4j/TestMultilineValues.java new file mode 100644 index 00000000..c1786cea --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestMultilineValues.java @@ -0,0 +1,106 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestMultilineValues { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("multiline_values.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals(""" + A multiline value + continued on the next line + + and also down here.""", + GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals(""" + A multiline value starting + on a new line.""", + GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key04")); + } + + @Test + public void testKey05() { + Assertions.assertEquals(""" + A multiline value with non-standard + + indentation.""", + GetFileHelper.getMessage(bundle, "key05")); + } + + @Test + public void testKey06() { + Assertions.assertEquals(""" + A multiline value with placeables + at the beginning and the end + of lines.""", + GetFileHelper.getMessage(bundle, "key06")); + } + + @Test + public void testKey07() { + Assertions.assertEquals("A multiline value starting and ending with a placeable", GetFileHelper.getMessage(bundle, "key07")); + } + + @Test + public void testKey08() { + Assertions.assertEquals("Leading and trailing whitespace.", GetFileHelper.getMessage(bundle, "key08")); + } + + @Test + public void testKey09() { + Assertions.assertEquals(""" + zero + three + two + one + zero""", + GetFileHelper.getMessage(bundle, "key09")); + } + + @Test + public void testKey10() { + Assertions.assertEquals(""" + two + zero + four""", + GetFileHelper.getMessage(bundle, "key10")); + } + + @Test + public void testKey11() { + Assertions.assertEquals(""" + two + zero""", + GetFileHelper.getMessage(bundle, "key11")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestNumbers.java b/src/test/java/net/quickwrite/fluent4j/TestNumbers.java new file mode 100644 index 00000000..5bc1759e --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestNumbers.java @@ -0,0 +1,127 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestNumbers { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("numbers.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testIntZero() { + Assertions.assertEquals("0", GetFileHelper.getMessage(bundle, "int-zero")); + } + + @Test + public void testIntPositive() { + Assertions.assertEquals("1", GetFileHelper.getMessage(bundle, "int-positive")); + } + + @Test + public void testIntNegative() { + Assertions.assertEquals("-1", GetFileHelper.getMessage(bundle, "int-negative")); + } + + @Test + public void testIntNegativeZero() { + Assertions.assertEquals("0", GetFileHelper.getMessage(bundle, "int-negative-zero")); + } + + @Test + public void testIntPositivePadded() { + Assertions.assertEquals("1", GetFileHelper.getMessage(bundle, "int-positive-padded")); + } + + @Test + public void testIntNegativePadded() { + Assertions.assertEquals("-1", GetFileHelper.getMessage(bundle, "int-negative-padded")); + } + + @Test + public void testIntZeroPadded() { + Assertions.assertEquals("0", GetFileHelper.getMessage(bundle, "int-zero-padded")); + } + + @Test + public void testIntNegativeZeroPadded() { + Assertions.assertEquals("0", GetFileHelper.getMessage(bundle, "int-negative-zero-padded")); + } + + @Test + public void testFloatZero() { + Assertions.assertEquals("0", GetFileHelper.getMessage(bundle, "float-zero")); + } + + @Test + public void testFloatPositive() { + Assertions.assertEquals("0.01", GetFileHelper.getMessage(bundle, "float-positive")); + } + + @Test + public void testFloatPositiveOne() { + Assertions.assertEquals("1.03", GetFileHelper.getMessage(bundle, "float-positive-one")); + } + + @Test + public void testFloatPositiveWithoutFraction() { + Assertions.assertEquals("1", GetFileHelper.getMessage(bundle, "float-positive-without-fraction")); + } + + @Test + public void testFloatNegative() { + Assertions.assertEquals("-0.01", GetFileHelper.getMessage(bundle, "float-negative")); + } + + @Test + public void testFloatNegativeOne() { + Assertions.assertEquals("-1.03", GetFileHelper.getMessage(bundle, "float-negative-one")); + } + + @Test + public void testFloatNegativeWithoutFraction() { + Assertions.assertEquals("-1", GetFileHelper.getMessage(bundle, "float-negative-without-fraction")); + } + + @Test + public void testFloatPositivePaddedLeft() { + Assertions.assertEquals("1.03", GetFileHelper.getMessage(bundle, "float-positive-padded-left")); + } + + @Test + public void testFloatPositivePaddedRight() { + Assertions.assertEquals("1.03", GetFileHelper.getMessage(bundle, "float-positive-padded-right")); + } + + @Test + public void testFloatPositivePaddedBoth() { + Assertions.assertEquals("1.03", GetFileHelper.getMessage(bundle, "float-positive-padded-both")); + } + + @Test + public void testFloatNegativePaddedLeft() { + Assertions.assertEquals("-1.03", GetFileHelper.getMessage(bundle, "float-negative-padded-left")); + } + + @Test + public void testFloatNegativePaddedRight() { + Assertions.assertEquals("-1.03", GetFileHelper.getMessage(bundle, "float-negative-padded-right")); + } + + @Test + public void testFloatNegativePaddedBoth() { + Assertions.assertEquals("-1.03", GetFileHelper.getMessage(bundle, "float-negative-padded-both")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestReferenceExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestReferenceExpressions.java new file mode 100644 index 00000000..c37fa4e2 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestReferenceExpressions.java @@ -0,0 +1,62 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.builder.FluentArgsBuilder; +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestReferenceExpressions { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("reference_expressions.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testMessageReferencePlaceable() { + Assertions.assertEquals("{msg}", GetFileHelper.getMessage(bundle, "message-reference-placeable")); + } + + @Test + public void testTermReferencePlaceable() { + Assertions.assertEquals("{-term}", GetFileHelper.getMessage(bundle, "term-reference-placeable")); + } + + @Test + public void testVariableReferencePlaceable() { + Assertions.assertEquals("{$var}", GetFileHelper.getMessage(bundle, "variable-reference-placeable")); + } + + @Test + public void testVariableReferenceSelector() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "variable-reference-selector")); + } + + @Test + public void testValidMessageReferencePlaceable() { + Assertions.assertEquals("Valid Message", GetFileHelper.getMessage(bundle, "valid-message-reference-placeable")); + } + + @Test + public void testValidTermReferencePlaceable() { + Assertions.assertEquals("Valid Term", GetFileHelper.getMessage(bundle, "valid-term-reference-placeable")); + } + + @Test + public void testValidVariableReferencePlaceable() { + Assertions.assertEquals("Value", + bundle.getMessage("valid-variable-reference-placeable", + new FluentArgsBuilder().set("var", "Value").build() + ).orElseThrow() + ); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestSelectExpressions.java b/src/test/java/net/quickwrite/fluent4j/TestSelectExpressions.java new file mode 100644 index 00000000..55eb18b7 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestSelectExpressions.java @@ -0,0 +1,47 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestSelectExpressions { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("select_expressions.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testNewMessages() { + Assertions.assertEquals("Other", GetFileHelper.getMessage(bundle, "new-messages")); + } + + @Test + public void testValidSelectorTermAttribute() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "valid-selector-term-attribute")); + } + + @Test + public void testEmptyVariant() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "empty-variant")); + } + + @Test + public void testReducedWhitespace() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "reduced-whitespace")); + } + + @Test + public void testNestedSelect() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "nested-select")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestSparseEntries.java b/src/test/java/net/quickwrite/fluent4j/TestSparseEntries.java new file mode 100644 index 00000000..417279c3 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestSparseEntries.java @@ -0,0 +1,55 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestSparseEntries { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("sparse_entries.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals(""" + Value + Continued + + + Over multiple + Lines""", + GetFileHelper.getMessage(bundle, "key03") + ); + } + + @Test + public void testKey05() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key05")); + } + + @Test + public void testKey06() { + Assertions.assertEquals("One", GetFileHelper.getMessage(bundle, "key06")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestTab.java b/src/test/java/net/quickwrite/fluent4j/TestTab.java new file mode 100644 index 00000000..1da580be --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestTab.java @@ -0,0 +1,37 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestTab { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("tab.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals("\tValue 01", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey03() { + Assertions.assertEquals("", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals("This line is indented by 4 spaces,", GetFileHelper.getMessage(bundle, "key04")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestTermParameters.java b/src/test/java/net/quickwrite/fluent4j/TestTermParameters.java new file mode 100644 index 00000000..9ea7bd43 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestTermParameters.java @@ -0,0 +1,42 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestTermParameters { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("term_parameters.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key01")); + } + + @Test + public void testKey02() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key02")); + } + + @Test + public void testKey03() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key03")); + } + + @Test + public void testKey04() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "key04")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestVariables.java b/src/test/java/net/quickwrite/fluent4j/TestVariables.java new file mode 100644 index 00000000..a8491160 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestVariables.java @@ -0,0 +1,58 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.builder.FluentArgsBuilder; +import net.quickwrite.fluent4j.util.args.FluentArgs; +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestVariables { + private FluentBundle bundle; + private FluentArgs arguments; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("variables.ftl"); + this.arguments = new FluentArgsBuilder().set("var", "Value").build(); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testKey01() { + Assertions.assertEquals( + "Value", + bundle.getMessage("key01", arguments).orElseThrow() + ); + } + + @Test + public void testKey02() { + Assertions.assertEquals( + "Value", + bundle.getMessage("key02", arguments).orElseThrow() + ); + } + + @Test + public void testKey03() { + Assertions.assertEquals( + "Value", + bundle.getMessage("key03", arguments).orElseThrow() + ); + } + + @Test + public void testKey04() { + Assertions.assertEquals( + "Value", + bundle.getMessage("key04", arguments).orElseThrow() + ); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestVariantKeys.java b/src/test/java/net/quickwrite/fluent4j/TestVariantKeys.java new file mode 100644 index 00000000..37c2ecaf --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestVariantKeys.java @@ -0,0 +1,42 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestVariantKeys { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("variant_keys.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertTrue(bundle.hasExceptions()); + } + + @Test + public void testSimpleIdentifier() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "simple-identifier")); + } + + @Test + public void testIdentifierSurroundedByWhitespace() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "identifier-surrounded-by-whitespace")); + } + + @Test + public void testIntNumberIdentifier() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "int-number")); + } + + @Test + public void testFloatNumberIdentifier() { + Assertions.assertEquals("Value", GetFileHelper.getMessage(bundle, "float-number")); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestWhitespaceInValue.java b/src/test/java/net/quickwrite/fluent4j/TestWhitespaceInValue.java new file mode 100644 index 00000000..068646da --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestWhitespaceInValue.java @@ -0,0 +1,37 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestWhitespaceInValue { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("whitespace_in_value.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } + + @Test + public void testKey() { + Assertions.assertEquals(""" + first line + + + + + + + last line""", + GetFileHelper.getMessage(bundle, "key") + ); + } +} diff --git a/src/test/java/net/quickwrite/fluent4j/TestZeroLength.java b/src/test/java/net/quickwrite/fluent4j/TestZeroLength.java new file mode 100644 index 00000000..298582b5 --- /dev/null +++ b/src/test/java/net/quickwrite/fluent4j/TestZeroLength.java @@ -0,0 +1,22 @@ +package net.quickwrite.fluent4j; + +import net.quickwrite.fluent4j.util.bundle.FluentBundle; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.io.IOException; + +public class TestZeroLength { + private FluentBundle bundle; + + @Before + public void setUp() throws IOException { + this.bundle = GetFileHelper.getFluentBundle("zero_length.ftl"); + } + + @Test + public void testIfExceptions() { + Assertions.assertFalse(bundle.hasExceptions()); + } +} diff --git a/src/test/resources/input/comments.ftl b/src/test/resources/input/comments.ftl index d3566930..638ac16e 100644 --- a/src/test/resources/input/comments.ftl +++ b/src/test/resources/input/comments.ftl @@ -13,8 +13,3 @@ foo = Foo # with indent ## Group Comment ### Resource Comment - -# Errors -#error -##error -###error diff --git a/src/test/resources/input/leading_dots.ftl b/src/test/resources/input/leading_dots.ftl index 0b9d6693..cd6ccd1c 100644 --- a/src/test/resources/input/leading_dots.ftl +++ b/src/test/resources/input/leading_dots.ftl @@ -50,27 +50,14 @@ key15 = {"."}Value } -# JUNK (variant must have a value) key16 = { 1 -> *[one] .Value } -# JUNK (unclosed placeable) key17 = { 1 -> *[one] Value .Continued } - -# JUNK (attr .Value must have a value) -key18 = -.Value - -key19 = -.attribute = Value - Continued - -key20 = -{"."}Value diff --git a/src/test/resources/input/literal_expressions.ftl b/src/test/resources/input/literal_expressions.ftl index 937b8a17..4124f5ca 100644 --- a/src/test/resources/input/literal_expressions.ftl +++ b/src/test/resources/input/literal_expressions.ftl @@ -1,3 +1,9 @@ string-expression = {"abc"} + number-expression = {123} -number-expression = {-3.14} + +negative-number-expression = {-42} + +float-expression = {3.141} + +negative-float-expression = {-6.282} diff --git a/src/test/resources/input/member_expressions.ftl b/src/test/resources/input/member_expressions.ftl index 8bee3cd7..9cf09233 100644 --- a/src/test/resources/input/member_expressions.ftl +++ b/src/test/resources/input/member_expressions.ftl @@ -1,19 +1,16 @@ ## Member expressions in placeables. -# OK Message attributes may be interpolated in values. message-attribute-expression-placeable = {msg.attr} -# ERROR Term attributes may not be used for interpolation. term-attribute-expression-placeable = {-term.attr} ## Member expressions in selectors. -# OK Term attributes may be used as selectors. term-attribute-expression-selector = {-term.attr -> *[key] Value } -# ERROR Message attributes may not be used as selectors. + message-attribute-expression-selector = {msg.attr -> *[key] Value } diff --git a/src/test/resources/input/messages.ftl b/src/test/resources/input/messages.ftl index dbc616ee..cd5637cd 100644 --- a/src/test/resources/input/messages.ftl +++ b/src/test/resources/input/messages.ftl @@ -3,7 +3,7 @@ key01 = Value key02 = Value .attr = Attribute -key02 = Value +key02 = Value2 .attr1 = Attribute 1 .attr2 = Attribute 2 diff --git a/src/test/resources/input/mixed_entries.ftl b/src/test/resources/input/mixed_entries.ftl index 99cc023d..444dc67e 100644 --- a/src/test/resources/input/mixed_entries.ftl +++ b/src/test/resources/input/mixed_entries.ftl @@ -9,7 +9,7 @@ key01 = .attr = Attribute -ą=Invalid identifier +ą=Custom Identifier ć=Another one # Message Comment diff --git a/src/test/resources/input/multiline_values.ftl b/src/test/resources/input/multiline_values.ftl index e3739bb5..bf50075c 100644 --- a/src/test/resources/input/multiline_values.ftl +++ b/src/test/resources/input/multiline_values.ftl @@ -51,10 +51,3 @@ key11 = two zero -key12 = -{"."} - four - -key13 = - four -{"."} diff --git a/src/test/resources/input/obsolete.ftl b/src/test/resources/input/obsolete.ftl deleted file mode 100644 index e0869e3a..00000000 --- a/src/test/resources/input/obsolete.ftl +++ /dev/null @@ -1,29 +0,0 @@ -### The syntax in this file has been discontinued. It is no longer part of the -### Fluent specification and should not be implemented nor used. We're keeping -### these fixtures around to protect against accidental syntax reuse. - - -## Variant lists. - -message-variant-list = - { - *[key] Value - } - --term-variant-list = - { - *[key] Value - } - - -## Variant expressions. - -message-variant-expression-placeable = {msg[case]} -message-variant-expression-selector = {msg[case] -> - *[key] Value -} - -term-variant-expression-placeable = {-term[case]} -term-variant-expression-selector = {-term[case] -> - *[key] Value -} diff --git a/src/test/resources/input/placeables.ftl b/src/test/resources/input/placeables.ftl deleted file mode 100644 index 7a1b280f..00000000 --- a/src/test/resources/input/placeables.ftl +++ /dev/null @@ -1,15 +0,0 @@ -nested-placeable = {{{1}}} -padded-placeable = { 1 } -sparse-placeable = { { 1 } } - -# ERROR Unmatched opening brace -unmatched-open1 = { 1 - -# ERROR Unmatched opening brace -unmatched-open2 = {{ 1 } - -# ERROR Unmatched closing brace -unmatched-close1 = 1 } - -# ERROR Unmatched closing brace -unmatched-close2 = { 1 }} diff --git a/src/test/resources/input/reference_expressions.ftl b/src/test/resources/input/reference_expressions.ftl index 5b03334f..224db747 100644 --- a/src/test/resources/input/reference_expressions.ftl +++ b/src/test/resources/input/reference_expressions.ftl @@ -4,11 +4,6 @@ message-reference-placeable = {msg} term-reference-placeable = {-term} variable-reference-placeable = {$var} -# Function references are invalid outside of call expressions. -# This parses as a valid MessageReference. -function-reference-placeable = {FUN} - - ## Reference expressions in selectors. variable-reference-selector = {$var -> @@ -23,8 +18,11 @@ message-reference-selector = {msg -> term-reference-selector = {-term -> *[key] Value } -# ERROR Function references are invalid outside of call expressions, and this -# parses as a MessageReference which isn't a valid selector. -function-expression-selector = {FUN -> - *[key] Value -} + +## Check if valid references work +valid-message-reference-placeable = {valid-msg} +valid-term-reference-placeable = {-valid-term} +valid-variable-reference-placeable = {$var} + +valid-msg = Valid Message +-valid-term = Valid Term diff --git a/src/test/resources/input/select_expressions.ftl b/src/test/resources/input/select_expressions.ftl index 603a1226..467b3227 100644 --- a/src/test/resources/input/select_expressions.ftl +++ b/src/test/resources/input/select_expressions.ftl @@ -6,33 +6,19 @@ new-messages = valid-selector-term-attribute = { -term.case -> - *[key] value + *[key] Value } # ERROR Term values are not valid selectors invalid-selector-term-value = { -term -> - *[key] value + *[key] Value } # ERROR CallExpressions on Terms are similar to TermReferences invalid-selector-term-variant = { -term(case: "nominative") -> - *[key] value - } - -# ERROR Nested expressions are not valid selectors -invalid-selector-nested-expression = - { { 3 } -> - *[key] default - } - -# ERROR Select expressions are not valid selectors -invalid-selector-select-expression = - { { $sel -> - *[key] value - } -> - *[key] default + *[key] Value } empty-variant = diff --git a/src/test/resources/input/select_indent.ftl b/src/test/resources/input/select_indent.ftl deleted file mode 100644 index 7455e935..00000000 --- a/src/test/resources/input/select_indent.ftl +++ /dev/null @@ -1,96 +0,0 @@ -select-1tbs-inline = { $selector -> - *[key] Value -} - -select-1tbs-newline = { -$selector -> - *[key] Value -} - -select-1tbs-indent = { - $selector -> - *[key] Value -} - -select-allman-inline = -{ $selector -> - *[key] Value - [other] Other -} - -select-allman-newline = -{ -$selector -> - *[key] Value -} - -select-allman-indent = -{ - $selector -> - *[key] Value -} - -select-gnu-inline = - { $selector -> - *[key] Value - } - -select-gnu-newline = - { -$selector -> - *[key] Value - } - -select-gnu-indent = - { - $selector -> - *[key] Value - } - -select-no-indent = -{ -$selector -> -*[key] Value -[other] Other -} - -select-no-indent-multiline = -{ -$selector -> -*[key] Value - Continued -[other] - Other - Multiline -} - -# ERROR (Multiline text must be indented) -select-no-indent-multiline = { $selector -> - *[key] Value -Continued without indent. -} - -select-flat = -{ -$selector --> -*[ -key -] Value -[ -other -] Other -} - -# Each line ends with 5 spaces. -select-flat-with-trailing-spaces = -{ -$selector --> -*[ -key -] Value -[ -other -] Other -} diff --git a/src/test/resources/input/special_chars.ftl b/src/test/resources/input/special_chars.ftl deleted file mode 100644 index 5224bad7..00000000 --- a/src/test/resources/input/special_chars.ftl +++ /dev/null @@ -1,14 +0,0 @@ -## OK - -bracket-inline = [Value] -dot-inline = .Value -star-inline = *Value - -## ERRORS - -bracket-newline = - [Value] -dot-newline = - .Value -star-newline = - *Value diff --git a/src/test/resources/input/terms.ftl b/src/test/resources/input/terms.ftl deleted file mode 100644 index 893188d4..00000000 --- a/src/test/resources/input/terms.ftl +++ /dev/null @@ -1,29 +0,0 @@ --term01 = Value - .attr = Attribute - --term02 = {""} - -# JUNK Missing value --term03 = - .attr = Attribute - -# JUNK Missing value -# < whitespace > --term04 = - .attr1 = Attribute 1 - -# JUNK Missing value --term05 = - -# JUNK Missing value -# < whitespace > --term06 = - -# JUNK Missing = --term07 - --term08=Value - .attr=Attribute - --term09 = Value - .attr = Attribute diff --git a/src/test/resources/input/variant_keys.ftl b/src/test/resources/input/variant_keys.ftl index 52f8ca61..346361b4 100644 --- a/src/test/resources/input/variant_keys.ftl +++ b/src/test/resources/input/variant_keys.ftl @@ -1,37 +1,37 @@ simple-identifier = { $sel -> - *[key] value + *[key] Value } identifier-surrounded-by-whitespace = { $sel -> - *[ key ] value + *[ key ] Value } int-number = { $sel -> - *[1] value + *[1] Value } float-number = { $sel -> - *[3.14] value + *[3.14] Value } # ERROR invalid-identifier = { $sel -> - *[two words] value + *[two words] Value } # ERROR invalid-int = { $sel -> - *[1 apple] value + *[1 apple] Value } # ERROR invalid-int = { $sel -> - *[3.14 apples] value + *[3.14 apples] Value }