google-nomulus/javatests/google/registry/ui/forms/FormFieldTest.java
jart 6082146d55 Prefer re2 over java.util.regex
Java's stock regex implementation doesn't guarantee linear time
complexity which makes it a security liability.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121159875
2016-05-13 23:16:07 -04:00

491 lines
16 KiB
Java

// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.ui.forms;
import static com.google.common.collect.Range.atLeast;
import static com.google.common.collect.Range.atMost;
import static com.google.common.collect.Range.closed;
import static com.google.common.truth.Truth.assertThat;
import static org.hamcrest.Matchers.equalTo;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.testing.NullPointerTester;
import com.google.re2j.Pattern;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Unit tests for {@link FormField}. */
@RunWith(JUnit4.class)
public class FormFieldTest {
private enum ICanHazEnum { LOL, CAT }
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void testConvert_nullString_notPresent() {
assertThat(FormField.named("lol").build().convert(null)).isAbsent();
}
@Test
public void testConvert_emptyString_returnsEmpty() {
assertThat(FormField.named("lol").build().convert("").get()).isEmpty();
}
@Test
public void testWithDefault_hasValue_returnsValue() {
assertThat(FormField.named("lol").withDefault("default").build().convert("return me!"))
.hasValue("return me!");
}
@Test
public void testWithDefault_nullValue_returnsDefault() {
assertThat(FormField.named("lol").withDefault("default").build().convert(null))
.hasValue("default");
}
@Test
public void testEmptyToNull_emptyString_notPresent() {
assertThat(FormField.named("lol").emptyToNull().build().convert("")).isAbsent();
}
@Test
public void testEmptyToNullRequired_emptyString_throwsFfe() {
thrown.expect(equalTo(new FormFieldException("This field is required.").propagate("lol")));
FormField.named("lol").emptyToNull().required().build().convert("");
}
@Test
public void testEmptyToNull_typeMismatch() {
thrown.expect(IllegalStateException.class);
FormField.named("lol", Object.class).emptyToNull();
}
@Test
public void testNamedLong() {
assertThat(FormField.named("lol", Long.class).build().convert(666L)).hasValue(666L);
}
@Test
public void testUppercased() {
FormField<String, String> field = FormField.named("lol").uppercased().build();
assertThat(field.convert(null)).isAbsent();
assertThat(field.convert("foo")).hasValue("FOO");
assertThat(field.convert("BAR")).hasValue("BAR");
}
@Test
public void testLowercased() {
FormField<String, String> field = FormField.named("lol").lowercased().build();
assertThat(field.convert(null)).isAbsent();
assertThat(field.convert("foo")).hasValue("foo");
assertThat(field.convert("BAR")).hasValue("bar");
}
@Test
public void testIn_passesThroughNull() {
FormField<String, String> field = FormField.named("lol")
.in(ImmutableSet.of("foo", "bar"))
.build();
assertThat(field.convert(null)).isAbsent();
}
@Test
public void testIn_valueIsContainedInSet() {
FormField<String, String> field = FormField.named("lol")
.in(ImmutableSet.of("foo", "bar"))
.build();
assertThat(field.convert("foo")).hasValue("foo");
assertThat(field.convert("bar")).hasValue("bar");
}
@Test
public void testIn_valueMissingFromSet() {
FormField<String, String> field = FormField.named("lol")
.in(ImmutableSet.of("foo", "bar"))
.build();
thrown.expect(equalTo(new FormFieldException("Unrecognized value.").propagate("lol")));
field.convert("omfg");
}
@Test
public void testRange_hasLowerBound_nullValue_passesThrough() {
assertThat(FormField.named("lol").range(atLeast(5)).build().convert(null)).isAbsent();
}
@Test
public void testRange_minimum_stringLengthEqualToMinimum_doesNothing() {
assertThat(FormField.named("lol").range(atLeast(5)).build().convert("hello")).hasValue("hello");
}
@Test
public void testRange_minimum_stringLengthShorterThanMinimum_throwsFfe() {
thrown.expect(FormFieldException.class);
thrown.expectMessage("Number of characters (3) not in range [4");
FormField.named("lol").range(atLeast(4)).build().convert("lol");
}
@Test
public void testRange_noLowerBound_nullValue_passThrough() {
assertThat(FormField.named("lol").range(atMost(5)).build().convert(null)).isAbsent();
}
@Test
public void testRange_maximum_stringLengthEqualToMaximum_doesNothing() {
assertThat(FormField.named("lol").range(atMost(5)).build().convert("hello")).hasValue("hello");
}
@Test
public void testRange_maximum_stringLengthShorterThanMaximum_throwsFfe() {
thrown.expect(FormFieldException.class);
thrown.expectMessage("Number of characters (6) not in range");
FormField.named("lol").range(atMost(5)).build().convert("omgomg");
}
@Test
public void testRange_numericTypes() {
FormField.named("lol", Byte.class).range(closed(5, 10)).build().convert((byte) 7);
FormField.named("lol", Short.class).range(closed(5, 10)).build().convert((short) 7);
FormField.named("lol", Integer.class).range(closed(5, 10)).build().convert(7);
FormField.named("lol", Long.class).range(closed(5, 10)).build().convert(7L);
FormField.named("lol", Float.class).range(closed(5, 10)).build().convert(7F);
FormField.named("lol", Double.class).range(closed(5, 10)).build().convert(7D);
}
@Test
public void testRange_typeMismatch() {
thrown.expect(IllegalStateException.class);
FormField.named("lol", Object.class).range(atMost(5));
}
@Test
public void testMatches_matches_doesNothing() {
assertThat(FormField.named("lol").matches(Pattern.compile("[a-z]+")).build().convert("abc"))
.hasValue("abc");
}
@Test
public void testMatches_mismatch_throwsFfeAndShowsDefaultErrorMessageWithPattern() {
thrown.expect(equalTo(new FormFieldException("Must match pattern: [a-z]+").propagate("lol")));
FormField.named("lol").matches(Pattern.compile("[a-z]+")).build().convert("123abc456");
}
@Test
public void testMatches_typeMismatch() {
thrown.expect(IllegalStateException.class);
FormField.named("lol", Object.class).matches(Pattern.compile("."));
}
@Test
public void testRetains() {
assertThat(
FormField.named("lol")
.retains(CharMatcher.anyOf("0123456789"))
.build()
.convert(" 123 1593-43 453 45 4 4 \t"))
.hasValue("1231593434534544");
}
@Test
public void testCast() {
assertThat(
FormField.named("lol")
.transform(
Integer.class,
new Function<String, Integer>() {
@Override
public Integer apply(String input) {
return Integer.parseInt(input);
}
})
.build()
.convert("123"))
.hasValue(123);
}
@Test
public void testCast_twice() {
assertThat(
FormField.named("lol")
.transform(
Object.class,
new Function<String, Object>() {
@Override
public Integer apply(String input) {
return Integer.parseInt(input);
}
})
.transform(String.class, Functions.toStringFunction())
.build()
.convert("123"))
.hasValue("123");
}
@Test
public void testAsList_null_notPresent() {
assertThat(FormField.named("lol").asList().build().convert(null)).isAbsent();
}
@Test
public void testAsList_empty_returnsEmpty() {
assertThat(FormField.named("lol").asList().build().convert(ImmutableList.<String>of()).get())
.isEmpty();
}
@Test
public void testAsListEmptyToNullRequired_empty_throwsFfe() {
thrown.expect(equalTo(new FormFieldException("This field is required.").propagate("lol")));
FormField.named("lol")
.asList()
.emptyToNull()
.required()
.build()
.convert(ImmutableList.<String>of());
}
@Test
public void testListEmptyToNull_empty_notPresent() {
assertThat(FormField.named("lol")
.asList()
.emptyToNull()
.build()
.convert(ImmutableList.<String>of()))
.isAbsent();
}
@Test
public void testAsEnum() {
FormField<String, ICanHazEnum> omgField = FormField.named("omg")
.asEnum(ICanHazEnum.class)
.build();
assertThat(omgField.convert("LOL").get()).isEqualTo(ICanHazEnum.LOL);
assertThat(omgField.convert("CAT").get()).isEqualTo(ICanHazEnum.CAT);
}
@Test
public void testAsEnum_lowercase_works() {
FormField<String, ICanHazEnum> omgField = FormField.named("omg")
.asEnum(ICanHazEnum.class)
.build();
assertThat(omgField.convert("lol").get()).isEqualTo(ICanHazEnum.LOL);
assertThat(omgField.convert("cat").get()).isEqualTo(ICanHazEnum.CAT);
}
@Test
public void testAsEnum_badInput_throwsFfe() {
FormField<String, ICanHazEnum> omgField = FormField.named("omg")
.asEnum(ICanHazEnum.class)
.build();
thrown.expect(equalTo(new FormFieldException("Enum ICanHazEnum does not contain 'helo'")
.propagate("omg")));
omgField.convert("helo");
}
@Test
public void testSplitList() {
FormField<String, List<String>> field = FormField.named("lol")
.asList(Splitter.on(',').omitEmptyStrings())
.build();
assertThat(field.convert("oh,my,goth").get())
.containsExactly("oh", "my", "goth")
.inOrder();
assertThat(field.convert("").get()).isEmpty();
assertThat(field.convert(null)).isAbsent();
}
@Test
public void testSplitSet() {
FormField<String, Set<String>> field = FormField.named("lol")
.uppercased()
.asSet(Splitter.on(',').omitEmptyStrings())
.build();
assertThat(field.convert("oh,my,goth").get())
.containsExactly("OH", "MY", "GOTH")
.inOrder();
assertThat(field.convert("").get()).isEmpty();
assertThat(field.convert(null)).isAbsent();
}
@Test
public void testAsList() {
assertThat(
FormField.named("lol").asList().build().convert(ImmutableList.of("lol", "cat", "")).get())
.containsExactly("lol", "cat", "").inOrder();
}
@Test
public void testAsList_trimmedEmptyToNullOnItems() {
assertThat(FormField.named("lol")
.trimmed()
.emptyToNull()
.matches(Pattern.compile("[a-z]+"))
.asList()
.range(closed(1, 2))
.build()
.convert(ImmutableList.of("lol\n", "\tcat "))
.get())
.containsExactly("lol", "cat").inOrder();
}
@Test
public void testAsList_nullElements_getIgnored() {
assertThat(FormField.named("lol")
.emptyToNull()
.asList()
.build()
.convert(ImmutableList.of("omg", ""))
.get())
.containsExactly("omg");
}
@Test
public void testAsListRequiredElements_nullElement_throwsFfeWithIndex() {
thrown.expect(equalTo(new FormFieldException("This field is required.")
.propagate(1)
.propagate("lol")));
FormField.named("lol")
.emptyToNull()
.required()
.asList()
.build()
.convert(ImmutableList.of("omg", ""));
}
@Test
public void testMapAsListRequiredElements_nullElement_throwsFfeWithIndexAndKey() {
thrown.expect(equalTo(new FormFieldException("This field is required.")
.propagate("cat")
.propagate(0)
.propagate("lol")));
FormField.mapNamed("lol")
.transform(String.class, new Function<Map<String, ?>, String>() {
@Override
public String apply(Map<String, ?> input) {
return FormField.named("cat")
.emptyToNull()
.required()
.build()
.extractUntyped(input)
.get();
}})
.asList()
.build()
.convert(ImmutableList.<Map<String, ?>>of(
ImmutableMap.of("cat", "")));
}
@Test
public void testAsListTrimmed_typeMismatch() {
FormField.named("lol").trimmed().asList();
thrown.expect(IllegalStateException.class);
FormField.named("lol").asList().trimmed();
}
@Test
public void testAsMatrix() {
assertThat(
FormField.named("lol", Integer.class)
.transform(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer input) {
return input * 2;
}})
.asList()
.asList()
.build()
.convert(Lists.cartesianProduct(ImmutableList.of(
ImmutableList.of(1, 2),
ImmutableList.of(3, 4))))
.get())
.containsExactly(
ImmutableList.of(2, 6),
ImmutableList.of(2, 8),
ImmutableList.of(4, 6),
ImmutableList.of(4, 8)).inOrder();
}
@Test
public void testAsSet() {
assertThat(FormField.named("lol")
.asSet()
.build()
.convert(ImmutableList.of("lol", "cat", "cat"))
.get())
.containsExactly("lol", "cat");
}
@Test
public void testTrimmed() {
assertThat(FormField.named("lol").trimmed().build().convert(" \thello \t\n")).hasValue("hello");
}
@Test
public void testTrimmed_typeMismatch() {
thrown.expect(IllegalStateException.class);
FormField.named("lol", Object.class).trimmed();
}
@Test
public void testAsBuilder() {
FormField<String, String> field = FormField.named("omg").uppercased().build();
assertThat(field.name()).isEqualTo("omg");
assertThat(field.convert("hello")).hasValue("HELLO");
field = field.asBuilder().build();
assertThat(field.name()).isEqualTo("omg");
assertThat(field.convert("hello")).hasValue("HELLO");
}
@Test
public void testAsBuilderNamed() {
FormField<String, String> field = FormField.named("omg").uppercased().build();
assertThat(field.name()).isEqualTo("omg");
assertThat(field.convert("hello")).hasValue("HELLO");
field = field.asBuilderNamed("bog").build();
assertThat(field.name()).isEqualTo("bog");
assertThat(field.convert("hello")).hasValue("HELLO");
}
@Test
public void testNullness() {
NullPointerTester tester = new NullPointerTester()
.setDefault(Class.class, Object.class)
.setDefault(Function.class, Functions.identity())
.setDefault(Pattern.class, Pattern.compile("."))
.setDefault(Range.class, Range.all())
.setDefault(Map.class, ImmutableMap.of())
.setDefault(Set.class, ImmutableSet.of())
.setDefault(String.class, "hello.com");
tester.testAllPublicStaticMethods(FormField.class);
tester.testAllPublicInstanceMethods(FormField.named("lol"));
tester.testAllPublicInstanceMethods(FormField.named("lol").build());
}
}