Skip to content

Commit fb29367

Browse files
committed
docs/tests: strengthen Moon codec fuzzing
1 parent f067bb8 commit fb29367

File tree

3 files changed

+509
-17
lines changed

3 files changed

+509
-17
lines changed

crates/loro/examples/moon_jsonschema_fuzz.rs

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@ use std::process::Command;
44
use std::time::{SystemTime, UNIX_EPOCH};
55

66
use loro::{
7-
ExpandType, ExportMode, Frontiers, LoroDoc, LoroValue, StyleConfig, StyleConfigMap, Timestamp,
8-
ToJson, TreeParentId, VersionVector,
7+
Container, ExpandType, ExportMode, Frontiers, LoroDoc, LoroValue, StyleConfig, StyleConfigMap,
8+
Timestamp, ToJson, TreeParentId, ValueOrContainer, VersionVector,
99
};
1010
use rand::{rngs::StdRng, Rng, SeedableRng};
1111

12+
fn configure_styles(doc: &LoroDoc) {
13+
let mut styles = StyleConfigMap::new();
14+
styles.insert(
15+
"bold".into(),
16+
StyleConfig {
17+
expand: ExpandType::After,
18+
},
19+
);
20+
styles.insert(
21+
"link".into(),
22+
StyleConfig {
23+
expand: ExpandType::Before,
24+
},
25+
);
26+
doc.config_text_style(styles);
27+
}
28+
1229
fn usage() -> ! {
1330
eprintln!(
1431
r#"moon_jsonschema_fuzz (loro)
@@ -160,6 +177,23 @@ fn first_json_diff_path(
160177
}
161178
}
162179

180+
fn frontiers_sorted_strings(frontiers: &Frontiers) -> Vec<String> {
181+
let mut ids: Vec<String> = frontiers.iter().map(|id| id.to_string()).collect();
182+
ids.sort();
183+
ids
184+
}
185+
186+
fn richtext_json_child_text(doc: &LoroDoc) -> anyhow::Result<serde_json::Value> {
187+
let map = doc.get_map("map");
188+
let Some(ValueOrContainer::Container(Container::Map(child_map))) = map.get("child_map") else {
189+
anyhow::bail!("missing map.child_map container")
190+
};
191+
let Some(ValueOrContainer::Container(Container::Text(child_text))) = child_map.get("t") else {
192+
anyhow::bail!("missing map.child_map.t container")
193+
};
194+
Ok(child_text.get_richtext_value().to_json_value())
195+
}
196+
163197
fn apply_random_ops(
164198
doc: &LoroDoc,
165199
seed: u64,
@@ -170,20 +204,7 @@ fn apply_random_ops(
170204
let mut rng = StdRng::seed_from_u64(seed);
171205
let peer_ids = if peer_ids.is_empty() { &[1] } else { peer_ids };
172206

173-
let mut styles = StyleConfigMap::new();
174-
styles.insert(
175-
"bold".into(),
176-
StyleConfig {
177-
expand: ExpandType::After,
178-
},
179-
);
180-
styles.insert(
181-
"link".into(),
182-
StyleConfig {
183-
expand: ExpandType::Before,
184-
},
185-
);
186-
doc.config_text_style(styles);
207+
configure_styles(doc);
187208

188209
let mut active_peer = peer_ids[0];
189210
doc.set_peer_id(active_peer)?;
@@ -554,6 +575,7 @@ fn main() -> anyhow::Result<()> {
554575
from: Cow::Borrowed(&start_vv),
555576
})?;
556577
let expected_doc = LoroDoc::new();
578+
configure_styles(&expected_doc);
557579
if let Some(base_snapshot) = &base_snapshot_blob {
558580
expected_doc.import(base_snapshot)?;
559581
}
@@ -565,13 +587,35 @@ fn main() -> anyhow::Result<()> {
565587

566588
let out_blob = run_encode_jsonschema(&node_bin, &cli_js, &json)?;
567589
let got_doc = LoroDoc::new();
590+
configure_styles(&got_doc);
568591
if let Some(base_snapshot) = &base_snapshot_blob {
569592
got_doc.import(base_snapshot)?;
570593
}
571594
got_doc.import(&out_blob)?;
572595
let got = got_doc.get_deep_value().to_json_value();
573596

574-
if got != expected {
597+
let expected_vv = expected_doc.oplog_vv();
598+
let got_vv = got_doc.oplog_vv();
599+
600+
let expected_frontiers = expected_doc.state_frontiers();
601+
let got_frontiers = got_doc.state_frontiers();
602+
let end_frontiers = doc.state_frontiers();
603+
604+
let expected_rich_root = expected_doc.get_text("text").get_richtext_value().to_json_value();
605+
let got_rich_root = got_doc.get_text("text").get_richtext_value().to_json_value();
606+
let expected_rich_child = richtext_json_child_text(&expected_doc)?;
607+
let got_rich_child = richtext_json_child_text(&got_doc)?;
608+
609+
let ok = got == expected
610+
&& got_vv == end
611+
&& expected_vv == end
612+
&& frontiers_sorted_strings(&got_frontiers) == frontiers_sorted_strings(&end_frontiers)
613+
&& frontiers_sorted_strings(&expected_frontiers)
614+
== frontiers_sorted_strings(&end_frontiers)
615+
&& got_rich_root == expected_rich_root
616+
&& got_rich_child == expected_rich_child;
617+
618+
if !ok {
575619
let case_dir = out_dir.join(format!("case-{case_seed}"));
576620
std::fs::create_dir_all(&case_dir)?;
577621

@@ -586,6 +630,10 @@ fn main() -> anyhow::Result<()> {
586630
write_json(&case_dir.join("expected.json"), &expected)?;
587631
write_json(&case_dir.join("got.json"), &got)?;
588632
write_json(&case_dir.join("expected_local.json"), &expected_local)?;
633+
write_json(&case_dir.join("expected_richtext_root.json"), &expected_rich_root)?;
634+
write_json(&case_dir.join("got_richtext_root.json"), &got_rich_root)?;
635+
write_json(&case_dir.join("expected_richtext_child.json"), &expected_rich_child)?;
636+
write_json(&case_dir.join("got_richtext_child.json"), &got_rich_child)?;
589637

590638
let start_ids: Option<Vec<String>> =
591639
start_frontiers.as_ref().map(|f| f.iter().map(|id| id.to_string()).collect());
@@ -595,8 +643,16 @@ fn main() -> anyhow::Result<()> {
595643
"commit_every": commit_every,
596644
"peers": peer_ids,
597645
"start_frontiers": start_ids,
646+
"end_frontiers": frontiers_sorted_strings(&end_frontiers),
647+
"expected_frontiers": frontiers_sorted_strings(&expected_frontiers),
648+
"got_frontiers": frontiers_sorted_strings(&got_frontiers),
649+
"end_vv": format!("{end:?}"),
650+
"expected_vv": format!("{expected_vv:?}"),
651+
"got_vv": format!("{got_vv:?}"),
598652
"diff_path": first_json_diff_path(&got, &expected, "$"),
599653
"local_diff_path": first_json_diff_path(&got, &expected_local, "$"),
654+
"richtext_root_diff_path": first_json_diff_path(&got_rich_root, &expected_rich_root, "$"),
655+
"richtext_child_diff_path": first_json_diff_path(&got_rich_child, &expected_rich_child, "$"),
600656
});
601657
write_json(&case_dir.join("meta.json"), &meta)?;
602658

0 commit comments

Comments
 (0)