Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/main/java/build/buf/protovalidate/Format.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ private static String formatString(Val val) {
}
return val.value().toString();
case Bytes:
return new String((byte[]) val.value(), StandardCharsets.UTF_8);
String byteStr = new String((byte[]) val.value(), StandardCharsets.UTF_8);
// Collapse any contiguous placeholders into one
return byteStr.replaceAll("\\ufffd+", "\ufffd");
case Double:
Optional<String> result = validateNumber(val);
if (result.isPresent()) {
Expand Down
48 changes: 29 additions & 19 deletions src/test/java/build/buf/protovalidate/FormatTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Named;
Expand Down Expand Up @@ -79,34 +79,33 @@ class FormatTest {
"object inside map");

@BeforeAll
static void setUp() throws Exception {
byte[] encoded =
Files.readAllBytes(
Paths.get("src/test/resources/testdata/string_ext_" + CEL_SPEC_VERSION + ".textproto"));
String data = new String(encoded, StandardCharsets.UTF_8);
SimpleTestFile.Builder bldr = SimpleTestFile.newBuilder();
TextFormat.getParser().merge(data, bldr);
SimpleTestFile testData = bldr.build();

List<SimpleTestSection> sections = testData.getSectionList();
private static void setUp() throws Exception {
// The test data from the cel-spec conformance tests
List<SimpleTestSection> celSpecSections =
loadTestData("src/test/resources/testdata/string_ext_" + CEL_SPEC_VERSION + ".textproto");
// Our supplemental tests of functionality not in the cel conformance file, but defined in the
// spec.
List<SimpleTestSection> supplementalSections =
loadTestData("src/test/resources/testdata/string_ext_supplemental.textproto");

// Combine the test data from both files into one
List<SimpleTestSection> sections =
Stream.concat(celSpecSections.stream(), supplementalSections.stream())
.collect(Collectors.toList());

// Find the format tests which test successful formatting
// Defaults to an empty list if nothing is found
formatTests =
sections.stream()
.filter(s -> s.getName().equals("format"))
.findFirst()
.map(SimpleTestSection::getTestList)
.orElse(Collections.emptyList());
.flatMap(s -> s.getTestList().stream())
.collect(Collectors.toList());

// Find the format error tests which test errors during formatting
// Defaults to an empty list if nothing is found
formatErrorTests =
sections.stream()
.filter(s -> s.getName().equals("format_errors"))
.findFirst()
.map(SimpleTestSection::getTestList)
.orElse(Collections.emptyList());
.flatMap(s -> s.getTestList().stream())
.collect(Collectors.toList());

env = Env.newEnv(Library.Lib(new ValidateLibrary()));
}
Expand All @@ -127,6 +126,17 @@ void testFormatError(SimpleTest test) {
assertThat(result.getVal().type().typeEnum()).isEqualTo(TypeEnum.Err);
}

// Loads test data from the given text format file
private static List<SimpleTestSection> loadTestData(String fileName) throws Exception {
byte[] encoded = Files.readAllBytes(Paths.get(fileName));
String data = new String(encoded, StandardCharsets.UTF_8);
SimpleTestFile.Builder bldr = SimpleTestFile.newBuilder();
TextFormat.getParser().merge(data, bldr);
SimpleTestFile testData = bldr.build();

return testData.getSectionList();
}

// Runs a test by extending the cel environment with the specified
// types, variables and declarations, then evaluating it with the cel runtime.
private static Program.EvalResult evaluate(SimpleTest test) {
Expand Down
26 changes: 26 additions & 0 deletions src/test/resources/testdata/string_ext_supplemental.textproto
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# proto-file: ../../../proto/cel/expr/conformance/test/simple.proto
# proto-message: cel.expr.conformance.test.SimpleTestFile

# Ideally these tests should be in the cel-spec conformance test suite.
# Until they are added, we can use this to test for additional functionality
# listed in the spec.

name: "string_ext_supplemental"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other tests we could add here involving precision and insignificant digits, but the spec isn't super clear on the behavior. For example, should values be rounded or truncated?

description: "Supplemental tests for the strings extension library."
section: {
name: "format"
test: {
name: "bytes support for string with invalid utf-8 encoding"
expr: '"%s".format([b"\xF0abc\x8C\xF0xyz"])'
value: {
string_value: '\ufffdabc\ufffdxyz',
}
}
test: {
name: "bytes support for string with only invalid utf-8 sequences"
expr: '"%s".format([b"\xF0\x8C\xF0"])'
value: {
string_value: '\ufffd',
}
}
}