Skip to content

Conversation

@smaye81
Copy link
Contributor

@smaye81 smaye81 commented May 28, 2025

Apologies for the large PR. The logical way to split this up is for Format.java to be its own PR with everything else separate but it may just be easier to review this all at once. So, an easy way to review is:

  • Format.java for all the formatting fixes
  • Everything else that runs the conformance tests

This adds conformance testing to our implementation of string.format. cel-java does not currently provide a string.format function so we implement our own and add it to the protovalidate-java CEL runtime.

While formatting is not (yet) a part of the cel-spec, they do provide conformance test data for validating behavior. So, to ensure we are conformant, we use this test data and run it against our implementation.

See the test data here. Note that this file contains various sections for testing. However, we are only concerned with the format and format_errors sections. In addition, since we are only testing for formatting, we do not handle every oneof case or variation in the SimpleTest definition -- only expected results or evaluation errors. If others are added down the road in future versions of the spec, we can adjust these tests.

There are few tests marked as skipped in FormatTest as these seem to be related to issues in cel-java's runtime (or in how we set up our environment) because the same issues happen when trying to use those expressions in protovalidate-java. Probably worth investigating or filing an issue for cel-java, but didn't want to hold up this PR.

// i.e. cel.expr.conformance.proto3.TestAllTypes. But, if we use managed mode it adds 'com'
// to the prefix. Additionally, we can't disable managed mode because the java_package option
// specified in these proto files is "dev.cel.expr.conformance.proto3". So, to get around this,
// we're generating these separately and specifying a java_package override of the package we need.
Copy link
Contributor Author

@smaye81 smaye81 May 28, 2025

Choose a reason for hiding this comment

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

We could just use one buf.gen.yaml for both cel generation steps, but then we'd have to specify the conformance version there also when we generate. Then we'd have the version in a 3rd place, which doesn't seem ideal.

Also, if there is an easier way to override the java_package with a blank value, that would also work here but I don't think there is.

@smaye81 smaye81 requested review from a user, pkwarren and rodaine May 28, 2025 15:07
}
return val.value().toString();
case Bytes:
return new String((byte[]) val.value(), StandardCharsets.UTF_8);
Copy link
Member

Choose a reason for hiding this comment

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

What does this do if the value is invalid UTF-8 here?

Copy link
Contributor Author

@smaye81 smaye81 May 28, 2025

Choose a reason for hiding this comment

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

Talked offline, but in the interest of visibility:

Currently this will print a placeholder �, but the strings.md doc on the cel-spec site specifies:

The value is formatted as if string(value) was performed and any invalid UTF-8 sequences are replaced with \ufffd. Multiple adjacent invalid UTF-8 sequences must be replaced with a single \ufffd.

So, this is currently non-conformant, but there are no actual conformance tests yet to cover this. Will implement this in a follow-up PR (with separate unit tests) if that's cool.

while (iter.hasNext().booleanValue()) {
Val v = iter.next();
builder.append(formatString(v));
if (index != val.size().intValue() - 1) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: Could use iter.hasNext() here instead of keeping track of an index.

env = Env.newEnv(Library.Lib(new ValidateLibrary()));

} catch (InvalidPathException | IOException e) {
fail(e);
Copy link
Member

Choose a reason for hiding this comment

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

I'd just add a throws Exception to the setUp method which will automatically fail the test.

@smaye81 smaye81 merged commit 256eb5c into main May 28, 2025
4 checks passed
@smaye81 smaye81 deleted the sayers/format_tests branch May 28, 2025 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants