From 998ee387d20ba06e4c0aa6c0f7ea4f09d16ec7e5 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Tue, 1 Apr 2025 22:40:05 +0100 Subject: [PATCH] Add integration tests --- backend/Cargo.lock | 1 + backend/reconcile/Cargo.toml | 4 +- backend/reconcile/test/examples/1.yml | 6 ++ backend/reconcile/test/examples/10.yml | 5 ++ backend/reconcile/test/examples/11.yml | 4 ++ backend/reconcile/test/examples/12.yml | 4 ++ backend/reconcile/test/examples/13.yml | 4 ++ backend/reconcile/test/examples/2.yml | 4 ++ backend/reconcile/test/examples/3.yml | 4 ++ backend/reconcile/test/examples/4.yml | 4 ++ backend/reconcile/test/examples/5.yml | 4 ++ backend/reconcile/test/examples/6.yml | 4 ++ backend/reconcile/test/examples/7.yml | 4 ++ backend/reconcile/test/examples/8.yml | 4 ++ backend/reconcile/test/examples/9.yml | 4 ++ backend/reconcile/tests/example_document.rs | 75 +++++++++++++++++++++ backend/reconcile/tests/test.rs | 47 +++++++++++++ 17 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 backend/reconcile/test/examples/1.yml create mode 100644 backend/reconcile/test/examples/10.yml create mode 100644 backend/reconcile/test/examples/11.yml create mode 100644 backend/reconcile/test/examples/12.yml create mode 100644 backend/reconcile/test/examples/13.yml create mode 100644 backend/reconcile/test/examples/2.yml create mode 100644 backend/reconcile/test/examples/3.yml create mode 100644 backend/reconcile/test/examples/4.yml create mode 100644 backend/reconcile/test/examples/5.yml create mode 100644 backend/reconcile/test/examples/6.yml create mode 100644 backend/reconcile/test/examples/7.yml create mode 100644 backend/reconcile/test/examples/8.yml create mode 100644 backend/reconcile/test/examples/9.yml create mode 100644 backend/reconcile/tests/example_document.rs create mode 100644 backend/reconcile/tests/test.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 5a5628f7..5ab0fa12 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1881,6 +1881,7 @@ dependencies = [ "insta", "pretty_assertions", "serde", + "serde_yaml", "test-case", ] diff --git a/backend/reconcile/Cargo.toml b/backend/reconcile/Cargo.toml index 99e7d6e6..9ef29647 100644 --- a/backend/reconcile/Cargo.toml +++ b/backend/reconcile/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true repository.workspace = true [dependencies] -serde = { version = "1.0.219", optional = true } +serde = { version = "1.0.219", optional = true, features = ["derive"] } [features] serde = [ "dep:serde" ] @@ -15,6 +15,8 @@ serde = [ "dep:serde" ] [dev-dependencies] insta = "1.41.1" pretty_assertions = "1.4.1" +serde = { version = "1.0.219", features = ["derive"] } +serde_yaml ="0.9.34" test-case = "3.3.1" [lints] diff --git a/backend/reconcile/test/examples/1.yml b/backend/reconcile/test/examples/1.yml new file mode 100644 index 00000000..ce90f51f --- /dev/null +++ b/backend/reconcile/test/examples/1.yml @@ -0,0 +1,6 @@ +# The `|` characters denote cursor positions which are stripped before the actual reconcile logic is run +--- +parent: You're Annual Savings Statement is available in our online portal +left: Your| annual record is available in our online portal| +right: You're Annual Savings information| is available online +expected: Your| annual record information| is available online| diff --git a/backend/reconcile/test/examples/10.yml b/backend/reconcile/test/examples/10.yml new file mode 100644 index 00000000..5b2183dc --- /dev/null +++ b/backend/reconcile/test/examples/10.yml @@ -0,0 +1,5 @@ +parent: marketplace +left: market| place +right: market|space +expected: market| placemarket|space + \ No newline at end of file diff --git a/backend/reconcile/test/examples/11.yml b/backend/reconcile/test/examples/11.yml new file mode 100644 index 00000000..549717de --- /dev/null +++ b/backend/reconcile/test/examples/11.yml @@ -0,0 +1,4 @@ +parent: Please remember to bring your laptop and charger +left: Please remember to bring your laptop| +right: Please remember to bring your |new |laptop and charger +expected: Please remember to bring your |new |laptop| \ No newline at end of file diff --git a/backend/reconcile/test/examples/12.yml b/backend/reconcile/test/examples/12.yml new file mode 100644 index 00000000..879b398f --- /dev/null +++ b/backend/reconcile/test/examples/12.yml @@ -0,0 +1,4 @@ +parent: Party A shall pay Party B +left: Party C shall pay Party B +right: Party A shall receive from Party B +expected: Party C shall receive from Party B diff --git a/backend/reconcile/test/examples/13.yml b/backend/reconcile/test/examples/13.yml new file mode 100644 index 00000000..e12c635b --- /dev/null +++ b/backend/reconcile/test/examples/13.yml @@ -0,0 +1,4 @@ +parent: Please submit your assignment by Friday +left: Please submit your |completed |assignment by Friday +right: Please submit your assignment |online |by Friday +expected: Please submit your |completed |assignment |online |by Friday diff --git a/backend/reconcile/test/examples/2.yml b/backend/reconcile/test/examples/2.yml new file mode 100644 index 00000000..77a03755 --- /dev/null +++ b/backend/reconcile/test/examples/2.yml @@ -0,0 +1,4 @@ +parent: +left: hi my friend| +right: hi there| +expected: hi my friend| there| diff --git a/backend/reconcile/test/examples/3.yml b/backend/reconcile/test/examples/3.yml new file mode 100644 index 00000000..8e2dd222 --- /dev/null +++ b/backend/reconcile/test/examples/3.yml @@ -0,0 +1,4 @@ +parent: Buy milk and eggs +left: Buy organic milk| and eggs| +right: Buy milk and eggs| and bread +expected: Buy organic milk| and eggs|| and bread diff --git a/backend/reconcile/test/examples/4.yml b/backend/reconcile/test/examples/4.yml new file mode 100644 index 00000000..f06d3287 --- /dev/null +++ b/backend/reconcile/test/examples/4.yml @@ -0,0 +1,4 @@ +parent: Meeting at 2pm in 会议室 +left: Meeting at |3pm in the 会议室 +right: Team meeting at 2pm in conference room| +expected: Team meeting at |3pm in conference room| the diff --git a/backend/reconcile/test/examples/5.yml b/backend/reconcile/test/examples/5.yml new file mode 100644 index 00000000..b1f3f45d --- /dev/null +++ b/backend/reconcile/test/examples/5.yml @@ -0,0 +1,4 @@ +parent: Send the report to the team +left: Send the |detailed |report to the |entire |team +right: Send the |quarterly |detailed |report to the team +expected: Send the |detailed |quarterly |detailed ||report to the |entire |team \ No newline at end of file diff --git a/backend/reconcile/test/examples/6.yml b/backend/reconcile/test/examples/6.yml new file mode 100644 index 00000000..16d25fb2 --- /dev/null +++ b/backend/reconcile/test/examples/6.yml @@ -0,0 +1,4 @@ +parent: Ready, Set go +left: Ready! Set go| +right: Ready, Set, go!| +expected: Ready! Set, go!|| diff --git a/backend/reconcile/test/examples/7.yml b/backend/reconcile/test/examples/7.yml new file mode 100644 index 00000000..579e9271 --- /dev/null +++ b/backend/reconcile/test/examples/7.yml @@ -0,0 +1,4 @@ +parent: "Total: $100" +left: "Total: |$150" +right: "Total: |€100" +expected: "Total: |$150 |€100" diff --git a/backend/reconcile/test/examples/8.yml b/backend/reconcile/test/examples/8.yml new file mode 100644 index 00000000..6c316ef6 --- /dev/null +++ b/backend/reconcile/test/examples/8.yml @@ -0,0 +1,4 @@ +parent: Start middle end +left: Start [important] middle end| +right: Start middle [critical] end| +expected: Start [important] middle [critical] end|| diff --git a/backend/reconcile/test/examples/9.yml b/backend/reconcile/test/examples/9.yml new file mode 100644 index 00000000..6f534b76 --- /dev/null +++ b/backend/reconcile/test/examples/9.yml @@ -0,0 +1,4 @@ +parent: A B C D +left: A X B D| +right: A B Y| +expected: A X B Y|| diff --git a/backend/reconcile/tests/example_document.rs b/backend/reconcile/tests/example_document.rs new file mode 100644 index 00000000..6bf845be --- /dev/null +++ b/backend/reconcile/tests/example_document.rs @@ -0,0 +1,75 @@ +use std::{fs, path::Path}; + +use pretty_assertions::assert_eq; +use reconcile::{CursorPosition, TextWithCursors, reconcile_with_cursors}; +use serde::Deserialize; + +/// ExampleDocument represents a test case for the reconciliation process. +/// It contains a parent string, left and right strings with cursor positions, +/// and the expected result after reconciliation. +/// +/// '|' characters in the left, right, and expected strings are treated as +/// cursor positions and are converted into `CursorPosition` objects. +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +pub struct ExampleDocument { + parent: String, + left: String, + right: String, + expected: String, +} + +impl ExampleDocument { + pub fn from_yaml(path: &Path) -> Self { + let file = fs::File::open(path).expect("Failed to open example file"); + serde_yaml::from_reader(file).expect("Failed to parse example file") + } + + pub fn parent(&self) -> String { self.parent.clone() } + + pub fn left(&self) -> TextWithCursors<'static> { + ExampleDocument::string_to_text_with_cursors(&self.left) + } + + pub fn right(&self) -> TextWithCursors<'static> { + ExampleDocument::string_to_text_with_cursors(&self.right) + } + + pub fn assert_eq(&self, result: TextWithCursors<'static>) { + let result_str = ExampleDocument::text_with_cursors_to_string(&result); + assert_eq!(result_str, self.expected); + } + + pub fn assert_eq_without_cursors(&self, result: &str) { + assert_eq!( + result, + ExampleDocument::string_to_text_with_cursors(&self.expected).text, + ); + } + + fn text_with_cursors_to_string<'a>(text: &TextWithCursors<'a>) -> String { + let mut result = text.text.clone().into_owned(); + for (i, cursor) in text.cursors.iter().enumerate() { + result.insert(cursor.char_index + i, '|'); + } + result + } + + fn string_to_text_with_cursors(text: &str) -> TextWithCursors<'static> { + let cursors = Self::parse_cursors(&text); + let text = text.replace("|", ""); + TextWithCursors::new_owned(text, cursors) + } + + fn parse_cursors(text: &str) -> Vec { + let mut cursors = Vec::new(); + for (i, c) in text.chars().enumerate() { + if c == '|' { + cursors.push(CursorPosition { + id: 0, + char_index: i - cursors.len(), + }); + } + } + cursors + } +} diff --git a/backend/reconcile/tests/test.rs b/backend/reconcile/tests/test.rs new file mode 100644 index 00000000..4b8382d0 --- /dev/null +++ b/backend/reconcile/tests/test.rs @@ -0,0 +1,47 @@ +mod example_document; +use std::{fs, path::Path}; + +use example_document::ExampleDocument; +use reconcile::{CursorPosition, TextWithCursors, reconcile, reconcile_with_cursors}; +use serde::Deserialize; + +#[test] +fn test_with_examples() { + let examples_dir = Path::new("test/examples"); + let mut entries = fs::read_dir(examples_dir) + .expect("Failed to read examples directory") + .collect::>(); + + entries.sort_by_key(|entry| { + let path = entry + .as_ref() + .expect("Failed to read directory entry") + .path(); + path.file_name() + .and_then(|name| name.to_str()) + .and_then(|name| name.split(".").next().unwrap().parse::().ok()) + .unwrap_or_default() + }); + + for entry in entries { + let entry = entry.expect("Failed to read directory entry"); + let path = entry.path(); + + if path.is_file() && path.extension().and_then(|ext| ext.to_str()) == Some("yml") { + let doc = ExampleDocument::from_yaml(&path); + println!("Testing with example from {}", path.display()); + + doc.assert_eq_without_cursors(&reconcile( + &doc.parent(), + &doc.left().text, + &doc.right().text, + )); + + doc.assert_eq(reconcile_with_cursors( + &doc.parent(), + doc.left(), + doc.right(), + )); + } + } +}