Skip to content

Commit

Permalink
Merge branch 'master' into upgrade-to-rc4
Browse files Browse the repository at this point in the history
  • Loading branch information
zslayton committed Jun 3, 2024
2 parents 80e8277 + f00c389 commit 4a20877
Show file tree
Hide file tree
Showing 26 changed files with 1,131 additions and 206 deletions.
134 changes: 134 additions & 0 deletions code-gen-projects/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Code generation projects

This directory contains 2 projects that are used in tests for code generation and serve as an example of
how to use `ion-cli` code generator under the `generate` subcommand with an existing project.

## Table of contents

* [/input](#input)
* [/schema](#schema)
* [/java](#java)
* [Gradle build process](#gradle-build-process)
* [/rust](#rust)
* [Cargo build process](#cargo-build-process)

## /input

This directory contains some good and bad test Ion files based on corresponding schema in `/schema`.

## /schema

This directory contains all the schema files used in testing code generation with `ion-cli` `generate` subcommand.

## /java

This directory contains a Java project called `code-gen-demo` which is a gradle project which has tests that uses the
generated code based
on schema file provided in `/schema` and test Ion file provided in `/input`.

### Gradle build process

To generate code as part of the build process of this project, a gradle build task is defined inside `build.gradle.kts`.
This task performs following steps:

- Gets the executable path for `ion-cli` through an environment variable `ION_CLI`. If the environment variable is not
set then it uses the local executable named `ion`.
- Sets the schema directory as `/schema` which will be used by `generate` subcommand to generate code for the schema
files inside it.
- Sets the path to output directory where the code will be generated and sets it as source directory.
- It runs the `ion-cli` `generate` subcommand with the set schema directory and a namespace where the code will be
generated.

Following is a sample build task you can add in an existing gradle project to generate code for your schemas,

```
val ionSchemaSourceCodeDir = "YOUR_SOURCE_SCHEMA_DIRECTORY"
val generatedIonSchemaModelDir = "${layout.buildDirectory.get()}/generated/java"
sourceSets {
main {
java.srcDir(generatedIonSchemaModelDir)
}
}
tasks {
val ionCodegen = create<Exec>("ionCodegen") {
inputs.files(ionSchemaSourceCodeDir)
outputs.file(generatedIonSchemaModelDir)
val ionCli = System.getenv("ION_CLI") ?: "ion"
commandLine(ionCli)
.args(
"beta", "generate",
"-l", "java",
"-n", "NAMESPACE_FOR_GENERATED_CODE",
"-d", ionSchemaSourceCodeDir,
"-o", generatedIonSchemaModelDir,
)
.workingDir(rootProject.projectDir)
}
withType<JavaCompile> {
options.encoding = "UTF-8"
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
options.release.set(8)
}
dependsOn(ionCodegen)
}
}
```

## /rust

This directory contains a Rust project called `code-gen-demo` which is a cargo project which has tests that uses the
generated code based
on schema file provided in `/schema` and test Ion file provided in `/input`.

### Cargo build process

To generate code as part of the build process of this cargo project, a cargo build script is defined in `build.rs`.
This task performs following steps:

- Gets the executable path for `ion-cli` through an environment variable `ION_CLI`. If the environment variable is not
set then it uses the local executable named `ion`.
- Sets the schema directory as `/schema` which will be used by `generate` subcommand to generate code for the schema
files inside it.
- Sets the path to output directory where the code will be generated (e.g. `OUT_DIR`).
- It runs the `ion-cli` `generate` subcommand with the set schema directory and a namespace where the code will be
generated.

Following is sample build script you can add in your existing cargo project to generate code using `ion-cli`.

```rust
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let out_dir = env::var("OUT_DIR").unwrap();

// Invokes the ion-cli executable using environment variable ION_CLI if present, otherwise uses local executable named `ion`
let ion_cli = env::var("ION_CLI").unwrap_or("ion".to_string());
println!("cargo:warn=Running command: {}", ion_cli);
let mut cmd = std::process::Command::new(ion_cli);
cmd.arg("beta")
.arg("generate")
.arg("-l")
.arg("rust")
.arg("-d")
.arg("YOUR_SOURCE_SCHEMA_DIRECTORY")
.arg("-o")
.arg(&out_dir);

println!("cargo:warn=Running: {:?}", cmd);

let output = cmd.output().expect("failed to execute process");

println!("status: {}", output.status);
io::stdout().write_all(&output.stdout).unwrap();
io::stderr().write_all(&output.stderr).unwrap();

assert!(output.status.success());

println!("cargo:rerun-if-changed=input/");
println!("cargo:rerun-if-changed=schema/");
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// nested struct with mismatched sequence type
{
A: "hello",
B: 12,
C: {
D: false,
E: (1 2 3) // expected list
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
B: 12,
C: {
D: 1e0, // expected type: bool
E: [1, 2, 3]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
A: "hello",
B: 12,
C: [1, 2, 3],
C: (1 2 3),
D: 10e2
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// simple struct with type mismatched sequence type
{
A: "hello",
B: 12,
C: ["foo", "bar", "baz"], // expected sexp
D: 10e2
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
A: "hello",
B: false, // expected field type: int
C: ["foo", "bar", "baz"],
C: ("foo" "bar" "baz"),
D: 10e2
}

3 changes: 2 additions & 1 deletion code-gen-projects/input/good/nested_struct/empty_values.ion
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// nested struct with empty string and zeros
// nested struct with empty string, list and zeros
{
C: {
D: false,
E: [],
},
A: "",
B: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
B: 12,
C: {
D: false,
E: [1, 2, 3]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
A: "hello",
C: {
D: false,
E: [1, 2, 3]
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// struct with empty list, empty string and zeros
{
C: [],
C: (),
A: "",
B: 0,
D: 0e0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{
A: "hello",
B: 12,
C: ["foo", "bar", "baz"],
C: ("foo" "bar" "baz"),
D: 10e2
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

// struct with unordered fields
{
C: ["foo", "bar", "baz"],
C: ("foo" "bar" "baz"),
A: "hello",
B: 12,
D: 10e2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ class CodeGenTest {
a.add("foo");
a.add("bar");
a.add("baz");
StructWithFields s = new StructWithFields("hello", 12, new AnonymousType2(a), 10e2);
StructWithFields s = new StructWithFields();

// set all the fields of `StructWithFields`
s.setA("hello");
s.setB(12);
s.setC(a);
s.setD(10e2);

// getter tests for `StructWithFields`
assertEquals("hello", s.getA(), "s.getA() should return \"hello\"");
Expand All @@ -39,18 +45,30 @@ class CodeGenTest {
assertEquals("hi", s.getA(), "s.getA() should return \"hi\"");
s.setB(6);
assertEquals(6, s.getB(), "s.getB() should return `6`");
s.setC(new AnonymousType2(new ArrayList<String>()));
s.setC(new ArrayList<String>());
assertEquals(true, s.getC().getValue().isEmpty(), "s.getC().isEmpty() should return `true`");
s.setD(11e3);
assertEquals(11e3 ,s.getD(), "s.getD() should return `11e3`");
}

@Test void getterAndSetterTestForNestedStruct() {
// getter tests for `NestedStruct`
NestedStruct n = new NestedStruct("hello", 12, new AnonymousType1(false));
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(1);
a.add(2);
a.add(3);
NestedStruct n = new NestedStruct();

// set all the fields of `NestedStruct`
n.setA("hello");
n.setB(12);
n.setC(false, a);

// getter tests for `NestedStruct`
assertEquals("hello", n.getA(), "n.getA() should return \"hello\"");
assertEquals(12, n.getB(), "n.getB() should return `12`");
assertEquals(false, n.getC().getD(), "n.getC().getD() should return `false`");
assertEquals(3, n.getC().getE().getValue().size(), "n.getC().getE().getValue().size() should return ArrayList fo size 3");

// setter tests for `NestedStruct`
n.setA("hi");
Expand All @@ -59,6 +77,8 @@ class CodeGenTest {
assertEquals(6, n.getB(), "s.getB() should return `6`");
n.getC().setD(true);
assertEquals(true, n.getC().getD(), "s.getC().getD() should return `true`");
n.getC().setE(new ArrayList<Integer>());
assertEquals(0, n.getC().getE().getValue().size(), "s.getC().getE().getValue().size() should return ArrayList fo size 0");
}

@Test void roundtripGoodTestForStructWithFields() throws IOException {
Expand Down
16 changes: 8 additions & 8 deletions code-gen-projects/rust/code-gen-demo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ mod tests {
}

#[test_resources("../../input/good/struct_with_fields/**/*.ion")]
fn roundtrip_good_test_generated_code_structs_with_fields(file_name: &str) -> IonResult<()> {
let ion_string = fs::read_to_string(file_name)?;
fn roundtrip_good_test_generated_code_structs_with_fields(file_name: &str) -> SerdeResult<()> {
let ion_string = fs::read_to_string(file_name).unwrap();
let mut reader = ReaderBuilder::new().build(ion_string.clone())?;
let mut buffer = Vec::new();
let mut text_writer = TextWriterBuilder::default().build(&mut buffer)?;
Expand All @@ -42,8 +42,8 @@ mod tests {
}

#[test_resources("../../input/bad/struct_with_fields/**/*.ion")]
fn roundtrip_bad_test_generated_code_structs_with_fields(file_name: &str) -> IonResult<()> {
let ion_string = fs::read_to_string(file_name)?;
fn roundtrip_bad_test_generated_code_structs_with_fields(file_name: &str) -> SerdeResult<()> {
let ion_string = fs::read_to_string(file_name).unwrap();
let mut reader = ReaderBuilder::new().build(ion_string.clone())?;
// read given Ion value using Ion reader
reader.next()?;
Expand All @@ -54,8 +54,8 @@ mod tests {
}

#[test_resources("../../input/good/nested_struct/**/*.ion")]
fn roundtrip_good_test_generated_code_nested_structs(file_name: &str) -> IonResult<()> {
let ion_string = fs::read_to_string(file_name)?;
fn roundtrip_good_test_generated_code_nested_structs(file_name: &str) -> SerdeResult<()> {
let ion_string = fs::read_to_string(file_name).unwrap();
let mut reader = ReaderBuilder::new().build(ion_string.clone())?;
let mut buffer = Vec::new();
let mut text_writer = TextWriterBuilder::default().build(&mut buffer)?;
Expand All @@ -75,8 +75,8 @@ mod tests {
}

#[test_resources("../../input/bad/nested_struct/**/*.ion")]
fn roundtrip_bad_test_generated_code_nested_structs(file_name: &str) -> IonResult<()> {
let ion_string = fs::read_to_string(file_name)?;
fn roundtrip_bad_test_generated_code_nested_structs(file_name: &str) -> SerdeResult<()> {
let ion_string = fs::read_to_string(file_name).unwrap();
let mut reader = ReaderBuilder::new().build(ion_string.clone())?;
// read given Ion value using Ion reader
reader.next()?;
Expand Down
3 changes: 2 additions & 1 deletion code-gen-projects/schema/nested_struct.isl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ type::{
B: int,
C: {
fields: {
D: bool
D: bool,
E: { type: list, element: int }
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion code-gen-projects/schema/struct_with_fields.isl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ type::{
fields: {
A: string,
B: int,
C: { element: string },
C: { element: string, type: sexp },
D: float,
}
}
Expand Down
Loading

0 comments on commit 4a20877

Please sign in to comment.