-
Notifications
You must be signed in to change notification settings - Fork 15
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
Adds integration tests for code generator #95
Conversation
* Adds input Ion files for testing (/code-gen-proejcts/input) * Adds schema files for testing (/code-gen-proejcts/schema) * Adds cargo crate in rust/code-gen-demo for testing in Rust * Adds gradle project in java/code-gen-demo for testing in Java * Adds build process in both Rust and java projects, to generate code while building and use it for tetsing * Adds tests in both Rust and Java projects
* Adds `code-gen-tests` in `ion-cli` to invoke both Rust and Java projects for testing
* Workflow modfiied to run code gene tests separately * Currently code gen tests only runs for ubuntu
@@ -33,7 +33,13 @@ jobs: | |||
uses: actions-rs/cargo@v1 | |||
with: | |||
command: test | |||
args: --verbose --workspace --all-features | |||
args: --verbose --workspace | |||
- name: Cargo Test - Code generation tests |
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.
(🗺️ PR tour) Adds GitHub Action for code generation tests. This currently only runs on ubuntu
to reduce time for running tests on code generation. code generation tests involve 3 steps:
- Cleans the predefined Java and Rust project targets.
- Generates code to these predefined projects using
ion-cli
subcommandgenerate
- Runs tests defined on these Java and Rust projects.
@@ -40,7 +40,7 @@ tempfile = "~3.5.0" | |||
|
|||
[features] | |||
default = [] | |||
beta-subcommands = ["dep:tera", "dep:convert_case"] | |||
experimental-code-gen = ["dep:tera", "dep:convert_case"] |
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.
(🗺️ PR tour) Renamed beta-subcommand
feature to experimental-code-gen
as its only used for code generation code and uses experimental-XYZ
signature similar to ion-rs
.
import static org.junit.jupiter.api.Assertions.*; | ||
import java.util.ArrayList; | ||
|
||
class CodeGenTest { |
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.
(🗺️ Pr tour) This class has tests for the generated code based on schema files in /code-gen-projects/schema/*
.
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.
Currently Java tests have manual tests for getter and setters but this can be changed to use roundtrip tests once read-write API generation is supported in Java.
} | ||
|
||
#[test] | ||
fn test_roundtrip_generated_code_structs_with_fields() -> IonResult<()> { |
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.
(🗺️ PR tour) Following are tests for the generated code in Rust based on /code-gen-projects/schema/*
(schema files) and code-gen-projects/input/*
(input files).
structs_with_fields.write_to(&mut text_writer)?; | ||
text_writer.flush()?; | ||
// compare given Ion value with round tripped Ion value written using abstract data type's `write_to` API | ||
assert_eq!( |
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.
(🗺️ PR tour) Roundtrip test has following steps:
- Read Ion data into data model(e.g.
StructWithFields
) usingread_from
API. - Write data model as Ion using
write_to
API. - Assert both expected Ion data and Ion data written by data model creates same
Element
.
@@ -6,7 +6,7 @@ public final class {{ target_kind_name }} { | |||
private final {{ field.value }} {{ field.name | camel }}; | |||
{% endfor %} | |||
|
|||
public {{ target_kind_name }}({% for field in fields -%}{{ field.value }} {{ field.name | camel }}{% if not loop.last %},{% endif %}{% endfor %}) { | |||
public {{ target_kind_name }}({% for field in fields | sort(attribute="name") -%}{{ field.value }} {{ field.name | camel }}{% if not loop.last %},{% endif %}{% endfor %}) { |
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.
(🗺️ PR tour) Sorting fields by field name ensures consistent constructor API generation for data model.
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.
We should not expose the constructor, if we can help it. Unless we generate overloaded constructors, using a constructor means that adding a new optional field is backwards incompatible. (And if you have two optional fields with the same type, then you've got a pretty good chance of having a method signature conflict.) On the other hand, if we use builders, then the generated order doesn't matter for us or for consumers of the generated code.
I don't think it needs to be solved now, but it does need to be called out as a current limitation, and it needs to be fixed before we can say that it is ready for customers to use.
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.
Right. Since currently the Java code generation doesn't support read-write API generation, I had to use the constructors for adding manual tests. I will create an issue for the work on builder generation support.
Reference issue: #97
|
||
#[cfg(feature = "experimental-code-gen")] | ||
#[test] | ||
fn roundtrip_tests_for_generated_code_gradle() -> Result<()> { |
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.
(🗺️ PR tour) These tests will invoke the predefined projects in code-gen-projects
, generates code based on their build process(build process invokes ion-cli
generate
subcommand) and then runs tests for these predfined projects.
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.
Question about the included Foo example, but otherwise lgtm.
code-gen-projects/java/code-gen-demo/src/main/java/org/example/Foo.java
Outdated
Show resolved
Hide resolved
inputs.files(ionSchemaSourceCodeDir) | ||
outputs.file(generatedIonSchemaModelDir) | ||
|
||
val ionCli = "../../../target/debug/ion" |
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.
You can pass the executable path using an environment variable. E.g.:
Set the path as an environment variable in the Rust integration test: https://github.com/popematt/ion-cli/blob/a24ecd23d659f6c0142b20bbc8a4771ac6a01c80/tests/codegen-tests.rs#L59-L65
Access the path from the gradle build script: https://github.com/popematt/ion-cli/blob/a24ecd23d659f6c0142b20bbc8a4771ac6a01c80/codegen-test-projects/java/build.gradle.kts#L33
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.
Follow-up PR: #98
let out_dir = env::var("OUT_DIR").unwrap(); | ||
|
||
// Invoke cargo CLI | ||
let ion_cli = "../../../target/debug/ion"; |
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.
You should pass in the path from the integration tests.
- This is not something that customers can copy. Getting it from the environment variable or the user path is something that customers can copy.
- Hard coded paths like this are brittle.
- This test project should not have to know anything about the outer project that contains it.
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.
Thanks for the explanation, I have modified according to your suggestions in a Follow-up PR: #98
Issue #88:
Description of changes:
This PR works on adding pre-defined code gen test projects and roundtrip tests for the generated code.
List of changes:
beta-subcommand
feature toexperimental-code-gen
(This makes it consistent withion-rs
on naming experimental feature. Also, since this feature is only used for code gen, usingbeta
wouldn't be specific)code-gen-projects
that has some pre-defined code generation projects for both Java(gradle projectcode-gen-demo
) and Rust(cargo cratecode-gene-demo
).while building and use it for tetsing
code-gen-tests
inion-cli
to invoke both Rust and Javaprojects for testing
-Modifies CI workflow
ubuntu
. Also, seeing error in running gradle project in GitHub Actions forwindows
platform returns error which needs to be investigated: https://github.com/desaikd/ion-cli/actions/runs/8574599832/job/23501774774)Sample of running tests on
ion-cli
for code generator:Tests
code-gen-tests
inion-cli
to invoke both Rust and Javacode-gen-projects
for both Rust and Java projectsBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.