-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add base64-decode #708
Add base64-decode #708
Conversation
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
|
||
@RunWith(Enclosed.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to have both valid and invalid input cases in the same file. This is the cleanest way I found to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about removing Parameterized
and just creating a different test for each of the 5 cases? I know it's more code, but I usually find parameterized tests (and especially JUnit's implementation of them) very hard to read and reason about. They're also very hard to rework if the one of the cases is modified, so there's a caveat (different setup, more assertions etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you in some cases but I think it really depends on the shape of the tests. With this style of test where there's a standard form with different values subbed in, I find parameterized tests easier to work with. We have a lot of examples of Parameterized
tests in JR.
That said, I'm ok moving to lowercase-p parameterized tests. I've done that in the latest commit. I think the important thing is that the form is only defined once. Hopefully this is a reasonable compromise for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I much prefer the new approach. I find using common builders/helpers a much nicer approach than an entire parametrized test, as you're still able to have a unique procedure for each case (without branching).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! We can move towards that as we introduce new tests.
import org.junit.runners.Parameterized; | ||
|
||
@RunWith(Parameterized.class) | ||
public class XPathFuncExprBase64DecodeTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this just be Base64DecodeTest
? I think the fact that it's nested in a way that makes it's clear it's testing an XPath expression.
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
|
||
@RunWith(Enclosed.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about removing Parameterized
and just creating a different test for each of the 5 cases? I know it's more code, but I usually find parameterized tests (and especially JUnit's implementation of them) very hard to read and reason about. They're also very hard to rework if the one of the cases is modified, so there's a caveat (different setup, more assertions etc).
// Copied from: https://github.com/brsanthu/migbase64/blob/master/src/main/java/com/migcomponents/migbase64/Base64.java | ||
// Irrelevant after Java8 | ||
@Override | ||
String encode(byte[] sArr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could encode
just throw an Unsupported
operation for now seeing as it's not being used and it's untested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only a whitespace change to make indentation consistent with rest of project. encode
was introduced and tested in #247.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry I got confused. I thought the whitespace change was just for the HEX
stuff, but I see now that you only added decode
to this file.
import org.junit.runners.Parameterized; | ||
|
||
@RunWith(Parameterized.class) | ||
public class EncodingDecodeTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this adds testing for hex
, but as far as I can see, the Base 64 cases are double coverage of the testing provides by XPathFuncExprBase64DecodeTest
. Would it make sense just to add a test for hex decoding instead? That could be a follow-up PR I reckon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a pretty strong preference to test at both levels because it's a pattern that exists throughout JR. There have been cases of functions that work when tested in isolation like this but not in forms. It's helpful to have the test coverage to differentiate the two, especially when there are regressions.
In this specific case, I further like the symmetry with EncodingEncodeTest
.
@@ -486,6 +487,9 @@ public Object eval(DataInstance model, EvaluationContext evalContext) { | |||
return XPathNodeset.shuffle((XPathNodeset) argVals[0], toNumeric(argVals[1]).longValue()); | |||
|
|||
throw new XPathUnhandledException("function \'randomize\' requires 1 or 2 arguments. " + args.length + " provided."); | |||
} else if (name.equals("base64-decode")) { | |||
assertArgsCount(name, args, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't look like there's a test for this line.
Discussion at https://forum.getodk.org/t/proposal-add-centroid-and-base64binary-to-string-functions/40289/5
What has been done to verify that this works as intended?
Added tests.
Why is this the best possible solution? Were any other approaches considered?
Name was selected with community input. Since we're not following an existing spec, I decided not to add an encoding parameter. In practice, most things are UTF-8 these days. We can add an encoding parameter later if needed.
We had talked about throwing an exception in case of invalid input but I decided to use a blank/null value instead. The problem with throwing an exception is that the exception can manifest as a Validate error and/or be thrown at undesirable moment if the input is not complete yet. With a blank value, it may be harder to track down unexpected values but I think it's an overall better experience.
I wanted to use standard Java
Base64
but that's not in Android until API 26. We already have a precedent for pulling code in from https://github.com/brsanthu/migbase64/blob/master/src/main/java/com/migcomponents/migbase64/Base64.java so I continued that.How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?
Isolated addition so all risk is to the new code which could be wrong.
Do we need any specific form for testing your changes? If so, please attach one.
See test.
Does this change require updates to documentation? If so, please file an issue here and include the link below.
getodk/xforms-spec#301