1#![allow(clippy::collapsible_match)]
2use serde_json::Value;
3use suture_driver::{DriverError, SemanticChange, SutureDriver};
4
5pub struct JsonDriver;
6
7impl JsonDriver {
8 pub fn new() -> Self {
9 Self
10 }
11
12 fn json_pointer_escape(s: &str) -> String {
13 s.replace('~', "~0").replace('/', "~1")
14 }
15
16 fn diff_values(old: &Value, new: &Value, path: &str) -> Vec<SemanticChange> {
17 let mut changes = Vec::new();
18
19 match (old, new) {
20 (Value::Object(old_map), Value::Object(new_map)) => {
21 let old_keys: std::collections::HashSet<&str> =
22 old_map.keys().map(|s| s.as_str()).collect();
23 let new_keys: std::collections::HashSet<&str> =
24 new_map.keys().map(|s| s.as_str()).collect();
25
26 for key in &old_keys {
27 if !new_keys.contains(key) {
28 let escaped = Self::json_pointer_escape(key);
29 let child_path = if path == "/" {
30 format!("/{escaped}")
31 } else {
32 format!("{path}/{escaped}")
33 };
34 changes.push(SemanticChange::Removed {
35 path: child_path,
36 old_value: old_map[*key].to_string(),
37 });
38 }
39 }
40
41 for key in &new_keys {
42 if !old_keys.contains(key) {
43 let escaped = Self::json_pointer_escape(key);
44 let child_path = if path == "/" {
45 format!("/{escaped}")
46 } else {
47 format!("{path}/{escaped}")
48 };
49 changes.push(SemanticChange::Added {
50 path: child_path,
51 value: new_map[*key].to_string(),
52 });
53 }
54 }
55
56 for key in &old_keys {
57 if let Some(new_val) = new_keys.contains(key).then(|| &new_map[*key]) {
58 let escaped = Self::json_pointer_escape(key);
59 let child_path = if path == "/" {
60 format!("/{escaped}")
61 } else {
62 format!("{path}/{escaped}")
63 };
64 changes.extend(Self::diff_values(&old_map[*key], new_val, &child_path));
65 }
66 }
67 }
68 (Value::Array(old_arr), Value::Array(new_arr)) => {
69 let max_len = old_arr.len().max(new_arr.len());
70
71 for i in 0..max_len {
72 let child_path = format!("{path}/{i}");
73 match (old_arr.get(i), new_arr.get(i)) {
74 (None, Some(new_val)) => {
75 changes.push(SemanticChange::Added {
76 path: child_path,
77 value: new_val.to_string(),
78 });
79 }
80 (Some(old_val), None) => {
81 changes.push(SemanticChange::Removed {
82 path: child_path,
83 old_value: old_val.to_string(),
84 });
85 }
86 (Some(old_val), Some(new_val)) => {
87 changes.extend(Self::diff_values(old_val, new_val, &child_path));
88 }
89 (None, None) => {}
90 }
91 }
92 }
93 (old_val, new_val) if old_val != new_val => {
94 changes.push(SemanticChange::Modified {
95 path: path.to_string(),
96 old_value: old_val.to_string(),
97 new_value: new_val.to_string(),
98 });
99 }
100 _ => {}
101 }
102
103 changes
104 }
105
106 fn merge_values(
107 base: &Value,
108 ours: &Value,
109 theirs: &Value,
110 ) -> Result<Option<Value>, DriverError> {
111 match (base, ours, theirs) {
112 (Value::Object(base_map), Value::Object(ours_map), Value::Object(theirs_map)) => {
113 let base_keys: std::collections::HashSet<&str> =
114 base_map.keys().map(|s| s.as_str()).collect();
115 let ours_keys: std::collections::HashSet<&str> =
116 ours_map.keys().map(|s| s.as_str()).collect();
117 let theirs_keys: std::collections::HashSet<&str> =
118 theirs_map.keys().map(|s| s.as_str()).collect();
119
120 let all_keys: std::collections::HashSet<&str> = base_keys
121 .iter()
122 .chain(ours_keys.iter())
123 .chain(theirs_keys.iter())
124 .copied()
125 .collect();
126
127 let mut merged = serde_json::Map::new();
128
129 for key in &all_keys {
130 let in_base = base_keys.contains(key);
131 let in_ours = ours_keys.contains(key);
132 let in_theirs = theirs_keys.contains(key);
133
134 match (in_base, in_ours, in_theirs) {
135 (true, true, false) => {
136 merged.insert((*key).to_string(), ours_map[*key].clone());
137 }
138 (true, false, true) => {
139 merged.insert((*key).to_string(), theirs_map[*key].clone());
140 }
141 (true, true, true) => {
142 let base_val = &base_map[*key];
143 let ours_val = &ours_map[*key];
144 let theirs_val = &theirs_map[*key];
145
146 if ours_val == theirs_val {
147 merged.insert((*key).to_string(), ours_val.clone());
148 } else if ours_val == base_val {
149 merged.insert((*key).to_string(), theirs_val.clone());
150 } else if theirs_val == base_val {
151 merged.insert((*key).to_string(), ours_val.clone());
152 } else if let Some(m) =
153 Self::merge_values(base_val, ours_val, theirs_val)?
154 {
155 merged.insert((*key).to_string(), m);
156 } else {
157 return Ok(None);
158 }
159 }
160 (false, true, true) => {
161 if ours_map[*key] == theirs_map[*key] {
162 merged.insert((*key).to_string(), ours_map[*key].clone());
163 } else {
164 return Ok(None);
165 }
166 }
167 (false, true, false) => {
168 merged.insert((*key).to_string(), ours_map[*key].clone());
169 }
170 (false, false, true) => {
171 merged.insert((*key).to_string(), theirs_map[*key].clone());
172 }
173 (true, false, false) => {}
174 (false, false, false) => {}
175 }
176 }
177
178 Ok(Some(Value::Object(merged)))
179 }
180 (Value::Array(base_arr), Value::Array(ours_arr), Value::Array(theirs_arr)) => {
181 let max_len = base_arr.len().max(ours_arr.len()).max(theirs_arr.len());
182 let mut merged = Vec::new();
183
184 for i in 0..max_len {
185 let base_val = base_arr.get(i);
186 let ours_val = ours_arr.get(i);
187 let theirs_val = theirs_arr.get(i);
188
189 match (base_val, ours_val, theirs_val) {
190 (None, Some(o), None) => merged.push(o.clone()),
191 (None, None, Some(t)) => merged.push(t.clone()),
192 (None, Some(o), Some(t)) => {
193 if o == t {
194 merged.push(o.clone());
195 } else {
196 return Ok(None);
197 }
198 }
199 (None, None, _) => {}
200 (Some(_), Some(o), None) => merged.push(o.clone()),
201 (Some(_), None, Some(t)) => merged.push(t.clone()),
202 (Some(_), None, None) => {}
203 (Some(b), Some(o), Some(t)) => {
204 if o == t {
205 merged.push(o.clone());
206 } else if o == b {
207 merged.push(t.clone());
208 } else if t == b {
209 merged.push(o.clone());
210 } else if let Some(m) = Self::merge_values(b, o, t)? {
211 merged.push(m);
212 } else {
213 return Ok(None);
214 }
215 }
216 }
217 }
218
219 Ok(Some(Value::Array(merged)))
220 }
221 (base_val, ours_val, theirs_val) => {
222 if ours_val == theirs_val {
223 Ok(Some(ours_val.clone()))
224 } else if ours_val == base_val {
225 Ok(Some(theirs_val.clone()))
226 } else if theirs_val == base_val {
227 Ok(Some(ours_val.clone()))
228 } else {
229 Ok(None)
230 }
231 }
232 }
233 }
234
235 fn format_change(change: &SemanticChange) -> String {
236 match change {
237 SemanticChange::Added { path, value } => {
238 format!(" ADDED {path}: {value}")
239 }
240 SemanticChange::Removed { path, old_value } => {
241 format!(" REMOVED {path}: {old_value}")
242 }
243 SemanticChange::Modified {
244 path,
245 old_value,
246 new_value,
247 } => {
248 format!(" MODIFIED {path}: {old_value} → {new_value}")
249 }
250 SemanticChange::Moved {
251 old_path,
252 new_path,
253 value,
254 } => {
255 format!(" MOVED {old_path} → {new_path}: {value}")
256 }
257 }
258 }
259}
260
261impl Default for JsonDriver {
262 fn default() -> Self {
263 Self::new()
264 }
265}
266
267impl SutureDriver for JsonDriver {
268 fn name(&self) -> &str {
269 "JSON"
270 }
271
272 fn supported_extensions(&self) -> &[&str] {
273 &[".json"]
274 }
275
276 fn diff(
277 &self,
278 base_content: Option<&str>,
279 new_content: &str,
280 ) -> Result<Vec<SemanticChange>, DriverError> {
281 let new_val: Value = serde_json::from_str(new_content)
282 .map_err(|e| DriverError::ParseError(e.to_string()))?;
283
284 match base_content {
285 None => {
286 let mut changes = Vec::new();
287 collect_all_paths(&new_val, "/".to_string(), &mut changes);
288 Ok(changes)
289 }
290 Some(base) => {
291 let old_val: Value = serde_json::from_str(base)
292 .map_err(|e| DriverError::ParseError(e.to_string()))?;
293 Ok(Self::diff_values(&old_val, &new_val, "/"))
294 }
295 }
296 }
297
298 fn format_diff(
299 &self,
300 base_content: Option<&str>,
301 new_content: &str,
302 ) -> Result<String, DriverError> {
303 let changes = self.diff(base_content, new_content)?;
304
305 if changes.is_empty() {
306 return Ok("no changes".to_string());
307 }
308
309 let lines: Vec<String> = changes.iter().map(Self::format_change).collect();
310 Ok(lines.join("\n"))
311 }
312
313 fn merge(&self, base: &str, ours: &str, theirs: &str) -> Result<Option<String>, DriverError> {
314 let base_val: Value =
315 serde_json::from_str(base).map_err(|e| DriverError::ParseError(e.to_string()))?;
316 let ours_val: Value =
317 serde_json::from_str(ours).map_err(|e| DriverError::ParseError(e.to_string()))?;
318 let theirs_val: Value =
319 serde_json::from_str(theirs).map_err(|e| DriverError::ParseError(e.to_string()))?;
320
321 match Self::merge_values(&base_val, &ours_val, &theirs_val)? {
322 Some(merged) => Ok(Some(
323 serde_json::to_string_pretty(&merged)
324 .map_err(|e| DriverError::SerializationError(e.to_string()))?,
325 )),
326 None => Ok(None),
327 }
328 }
329}
330
331fn collect_all_paths(val: &Value, path: String, out: &mut Vec<SemanticChange>) {
332 match val {
333 Value::Object(map) => {
334 for (key, child) in map {
335 let escaped = JsonDriver::json_pointer_escape(key);
336 let child_path = if path == "/" {
337 format!("/{escaped}")
338 } else {
339 format!("{path}/{escaped}")
340 };
341 collect_all_paths(child, child_path, out);
342 }
343 }
344 Value::Array(arr) => {
345 for (i, child) in arr.iter().enumerate() {
346 let child_path = format!("{path}/{i}");
347 collect_all_paths(child, child_path, out);
348 }
349 }
350 other => {
351 out.push(SemanticChange::Added {
352 path,
353 value: other.to_string(),
354 });
355 }
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362
363 #[test]
364 fn test_json_driver_name() {
365 let driver = JsonDriver::new();
366 assert_eq!(driver.name(), "JSON");
367 }
368
369 #[test]
370 fn test_json_driver_extensions() {
371 let driver = JsonDriver::new();
372 assert_eq!(driver.supported_extensions(), &[".json"]);
373 }
374
375 #[test]
376 fn test_diff_added_key() {
377 let driver = JsonDriver::new();
378 let old = r#"{"name": "Alice"}"#;
379 let new = r#"{"name": "Alice", "email": "alice@example.com"}"#;
380
381 let changes = driver.diff(Some(old), new).unwrap();
382 assert!(changes.contains(&SemanticChange::Added {
383 path: "/email".to_string(),
384 value: "\"alice@example.com\"".to_string(),
385 }));
386 }
387
388 #[test]
389 fn test_diff_removed_key() {
390 let driver = JsonDriver::new();
391 let old = r#"{"name": "Alice", "phone": "+1234567890"}"#;
392 let new = r#"{"name": "Alice"}"#;
393
394 let changes = driver.diff(Some(old), new).unwrap();
395 assert!(changes.contains(&SemanticChange::Removed {
396 path: "/phone".to_string(),
397 old_value: "\"+1234567890\"".to_string(),
398 }));
399 }
400
401 #[test]
402 fn test_diff_modified_key() {
403 let driver = JsonDriver::new();
404 let old = r#"{"name": "Alice"}"#;
405 let new = r#"{"name": "Bob"}"#;
406
407 let changes = driver.diff(Some(old), new).unwrap();
408 assert_eq!(changes.len(), 1);
409 assert_eq!(
410 changes[0],
411 SemanticChange::Modified {
412 path: "/name".to_string(),
413 old_value: "\"Alice\"".to_string(),
414 new_value: "\"Bob\"".to_string(),
415 }
416 );
417 }
418
419 #[test]
420 fn test_diff_nested() {
421 let driver = JsonDriver::new();
422 let old = r#"{"address": {"city": "NYC", "zip": "10001"}}"#;
423 let new = r#"{"address": {"city": "San Francisco", "zip": "10001"}}"#;
424
425 let changes = driver.diff(Some(old), new).unwrap();
426 assert!(changes.contains(&SemanticChange::Modified {
427 path: "/address/city".to_string(),
428 old_value: "\"NYC\"".to_string(),
429 new_value: "\"San Francisco\"".to_string(),
430 }));
431 }
432
433 #[test]
434 fn test_diff_new_file() {
435 let driver = JsonDriver::new();
436 let new = r#"{"name": "Alice", "age": 30}"#;
437
438 let changes = driver.diff(None, new).unwrap();
439 assert!(!changes.is_empty());
440 for change in &changes {
441 assert!(matches!(change, SemanticChange::Added { .. }));
442 }
443 }
444
445 #[test]
446 fn test_format_diff() {
447 let driver = JsonDriver::new();
448 let old = r#"{"name": "Alice"}"#;
449 let new = r#"{"name": "Bob", "email": "bob@example.com"}"#;
450
451 let output = driver.format_diff(Some(old), new).unwrap();
452 assert!(output.contains("MODIFIED"));
453 assert!(output.contains("ADDED"));
454 assert!(output.contains("/name"));
455 assert!(output.contains("/email"));
456 }
457
458 #[test]
459 fn test_format_diff_empty() {
460 let driver = JsonDriver::new();
461 let content = r#"{"name": "Alice"}"#;
462
463 let output = driver.format_diff(Some(content), content).unwrap();
464 assert_eq!(output, "no changes");
465 }
466
467 #[test]
468 fn test_array_changes() {
469 let driver = JsonDriver::new();
470 let old = r#"{"items": ["a", "b"]}"#;
471 let new = r#"{"items": ["a", "c", "d"]}"#;
472
473 let changes = driver.diff(Some(old), new).unwrap();
474 assert!(changes.contains(&SemanticChange::Modified {
475 path: "/items/1".to_string(),
476 old_value: "\"b\"".to_string(),
477 new_value: "\"c\"".to_string(),
478 }));
479 assert!(changes.contains(&SemanticChange::Added {
480 path: "/items/2".to_string(),
481 value: "\"d\"".to_string(),
482 }));
483 }
484
485 #[test]
486 fn test_merge_no_conflict() {
487 let driver = JsonDriver::new();
488 let base = r#"{"a": 1, "b": 2, "c": 3}"#;
489 let ours = r#"{"a": 10, "b": 2, "c": 3}"#;
490 let theirs = r#"{"a": 1, "b": 2, "c": 30}"#;
491
492 let result = driver.merge(base, ours, theirs).unwrap();
493 assert!(result.is_some());
494 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
495 assert_eq!(merged["a"], 10);
496 assert_eq!(merged["b"], 2);
497 assert_eq!(merged["c"], 30);
498 }
499
500 #[test]
501 fn test_merge_conflict() {
502 let driver = JsonDriver::new();
503 let base = r#"{"key": "original"}"#;
504 let ours = r#"{"key": "ours"}"#;
505 let theirs = r#"{"key": "theirs"}"#;
506
507 let result = driver.merge(base, ours, theirs).unwrap();
508 assert!(result.is_none());
509 }
510
511 #[test]
512 fn test_merge_both_add_different_keys() {
513 let driver = JsonDriver::new();
514 let base = r#"{"a": 1}"#;
515 let ours = r#"{"a": 1, "x": 100}"#;
516 let theirs = r#"{"a": 1, "y": 200}"#;
517
518 let result = driver.merge(base, ours, theirs).unwrap();
519 assert!(result.is_some());
520 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
521 assert_eq!(merged["a"], 1);
522 assert_eq!(merged["x"], 100);
523 assert_eq!(merged["y"], 200);
524 }
525
526 #[test]
527 fn test_merge_both_add_same_key() {
528 let driver = JsonDriver::new();
529 let base = r#"{"a": 1}"#;
530 let ours = r#"{"a": 1, "x": 100}"#;
531 let theirs = r#"{"a": 1, "x": 999}"#;
532
533 let result = driver.merge(base, ours, theirs).unwrap();
534 assert!(result.is_none());
535 }
536
537 #[test]
538 fn test_merge_nested() {
539 let driver = JsonDriver::new();
540 let base = r#"{"outer": {"inner": "base", "other": "keep"}}"#;
541 let ours = r#"{"outer": {"inner": "ours", "other": "keep"}}"#;
542 let theirs = r#"{"outer": {"inner": "base", "other": "changed"}}"#;
543
544 let result = driver.merge(base, ours, theirs).unwrap();
545 assert!(result.is_some());
546 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
547 assert_eq!(merged["outer"]["inner"], "ours");
548 assert_eq!(merged["outer"]["other"], "changed");
549 }
550
551 #[test]
552 fn test_merge_identical() {
553 let driver = JsonDriver::new();
554 let content = r#"{"a": 1, "b": 2}"#;
555
556 let result = driver.merge(content, content, content).unwrap();
557 assert!(result.is_some());
558 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
559 assert_eq!(merged["a"], 1);
560 assert_eq!(merged["b"], 2);
561 }
562
563 #[test]
564 fn test_correctness_merge_determinism() {
565 let driver = JsonDriver::new();
566 let base = r#"{"a": 1, "b": 2, "c": 3}"#;
567 let ours = r#"{"a": 10, "b": 2, "d": 4}"#;
568 let theirs = r#"{"a": 1, "b": 20, "e": 5}"#;
569
570 let r1 = driver.merge(base, ours, theirs).unwrap();
571 let r2 = driver.merge(base, theirs, ours).unwrap();
572 assert_eq!(r1.is_some(), r2.is_some());
573 if let (Some(m1), Some(m2)) = (r1, r2) {
574 let v1: Value = serde_json::from_str(&m1).unwrap();
575 let v2: Value = serde_json::from_str(&m2).unwrap();
576 assert_eq!(
577 v1, v2,
578 "merge(base, ours, theirs) must equal merge(base, theirs, ours)"
579 );
580 }
581 }
582
583 #[test]
584 fn test_correctness_merge_idempotency() {
585 let driver = JsonDriver::new();
586 let base = r#"{"a": 1, "b": 2}"#;
587 let ours = r#"{"a": 10, "b": 2, "c": 3}"#;
588
589 let result = driver.merge(base, ours, ours).unwrap();
590 assert!(result.is_some());
591 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
592 let expected: Value = serde_json::from_str(ours).unwrap();
593 assert_eq!(
594 merged, expected,
595 "merge(base, ours, ours) should equal ours"
596 );
597 }
598
599 #[test]
600 fn test_correctness_base_equals_ours() {
601 let driver = JsonDriver::new();
602 let base = r#"{"a": 1, "b": 2}"#;
603 let theirs = r#"{"a": 10, "b": 2, "c": 3}"#;
604
605 let result = driver.merge(base, base, theirs).unwrap();
606 assert!(result.is_some());
607 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
608 let expected: Value = serde_json::from_str(theirs).unwrap();
609 assert_eq!(
610 merged, expected,
611 "merge(base, base, theirs) should equal theirs"
612 );
613 }
614
615 #[test]
616 fn test_correctness_base_equals_theirs() {
617 let driver = JsonDriver::new();
618 let base = r#"{"a": 1, "b": 2}"#;
619 let ours = r#"{"a": 10, "b": 2, "c": 3}"#;
620
621 let result = driver.merge(base, ours, base).unwrap();
622 assert!(result.is_some());
623 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
624 let expected: Value = serde_json::from_str(ours).unwrap();
625 assert_eq!(
626 merged, expected,
627 "merge(base, ours, base) should equal ours"
628 );
629 }
630
631 #[test]
632 fn test_correctness_all_equal() {
633 let driver = JsonDriver::new();
634 let content = r#"{"x": 42, "y": "hello"}"#;
635
636 let result = driver.merge(content, content, content).unwrap();
637 assert!(result.is_some());
638 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
639 let expected: Value = serde_json::from_str(content).unwrap();
640 assert_eq!(merged, expected);
641 }
642
643 #[test]
644 fn test_correctness_both_add_different_keys() {
645 let driver = JsonDriver::new();
646 let base = r#"{"shared": true}"#;
647 let ours = r#"{"shared": true, "from_ours": 100}"#;
648 let theirs = r#"{"shared": true, "from_theirs": 200}"#;
649
650 let result = driver.merge(base, ours, theirs).unwrap();
651 assert!(result.is_some());
652 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
653 assert_eq!(merged["shared"], true);
654 assert_eq!(merged["from_ours"], 100);
655 assert_eq!(merged["from_theirs"], 200);
656 assert_eq!(merged.as_object().unwrap().len(), 3);
657 }
658
659 #[test]
660 fn test_correctness_both_modify_different_keys() {
661 let driver = JsonDriver::new();
662 let base = r#"{"a": 1, "b": 2, "c": 3}"#;
663 let ours = r#"{"a": 10, "b": 2, "c": 3}"#;
664 let theirs = r#"{"a": 1, "b": 2, "c": 30}"#;
665
666 let result = driver.merge(base, ours, theirs).unwrap();
667 assert!(result.is_some());
668 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
669 assert_eq!(merged["a"], 10, "ours change to 'a' should be kept");
670 assert_eq!(merged["c"], 30, "theirs change to 'c' should be kept");
671 assert_eq!(merged["b"], 2, "unchanged key should remain");
672 }
673
674 #[test]
675 fn test_correctness_both_modify_same_key_same_value() {
676 let driver = JsonDriver::new();
677 let base = r#"{"key": "original"}"#;
678 let ours = r#"{"key": "changed"}"#;
679 let theirs = r#"{"key": "changed"}"#;
680
681 let result = driver.merge(base, ours, theirs).unwrap();
682 assert!(result.is_some(), "identical changes should not conflict");
683 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
684 assert_eq!(merged["key"], "changed");
685 }
686
687 #[test]
688 fn test_correctness_both_modify_same_key_different_value() {
689 let driver = JsonDriver::new();
690 let base = r#"{"key": "original"}"#;
691 let ours = r#"{"key": "ours"}"#;
692 let theirs = r#"{"key": "theirs"}"#;
693
694 let result = driver.merge(base, ours, theirs).unwrap();
695 assert!(result.is_none(), "conflicting changes should return None");
696 }
697
698 #[test]
699 fn test_correctness_deeply_nested_merge() {
700 let driver = JsonDriver::new();
701 let base = r#"{"level1": {"level2": {"level3": {"a": 1, "b": 2, "c": 3}}}}"#;
702 let ours = r#"{"level1": {"level2": {"level3": {"a": 10, "b": 2, "c": 3}}}}"#;
703 let theirs = r#"{"level1": {"level2": {"level3": {"a": 1, "b": 2, "c": 30}}}}"#;
704
705 let result = driver.merge(base, ours, theirs).unwrap();
706 assert!(result.is_some());
707 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
708 assert_eq!(merged["level1"]["level2"]["level3"]["a"], 10);
709 assert_eq!(merged["level1"]["level2"]["level3"]["c"], 30);
710 assert_eq!(merged["level1"]["level2"]["level3"]["b"], 2);
711 }
712
713 #[test]
714 fn test_correctness_deeply_nested_merge_different_levels() {
715 let driver = JsonDriver::new();
716 let base = r#"{"outer": {"inner": "base", "other": "keep"}}"#;
717 let ours = r#"{"outer": {"inner": "ours", "other": "keep", "extra": 1}}"#;
718 let theirs = r#"{"outer": {"inner": "base", "other": "changed"}}"#;
719
720 let result = driver.merge(base, ours, theirs).unwrap();
721 assert!(result.is_some());
722 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
723 assert_eq!(merged["outer"]["inner"], "ours");
724 assert_eq!(merged["outer"]["other"], "changed");
725 assert_eq!(merged["outer"]["extra"], 1);
726 }
727
728 #[test]
729 fn test_correctness_unicode_keys_and_values() {
730 let driver = JsonDriver::new();
731 let base = r#"{"名前": "太郎", "age": 30}"#;
732 let ours = r#"{"名前": "太郎", "age": 31}"#;
733 let theirs = r#"{"名前": "次郎", "age": 30}"#;
734
735 let result = driver.merge(base, ours, theirs).unwrap();
736 assert!(result.is_some());
737 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
738 assert_eq!(merged["名前"], "次郎");
739 assert_eq!(merged["age"], 31);
740 }
741
742 #[test]
743 fn test_correctness_unicode_emoji_keys() {
744 let driver = JsonDriver::new();
745 let base = r#"{"🌍": "earth", "🚀": "rocket"}"#;
746 let ours = r#"{"🌍": "earth", "🚀": "falcon"}"#;
747 let theirs = r#"{"🌍": "terra", "🚀": "rocket"}"#;
748
749 let result = driver.merge(base, ours, theirs).unwrap();
750 assert!(result.is_some());
751 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
752 assert_eq!(merged["🌍"], "terra");
753 assert_eq!(merged["🚀"], "falcon");
754 }
755
756 #[test]
757 fn test_correctness_large_file() {
758 let driver = JsonDriver::new();
759 let mut base_obj = serde_json::Map::new();
760 let mut ours_obj = serde_json::Map::new();
761 let mut theirs_obj = serde_json::Map::new();
762
763 for i in 0..500 {
764 let key = format!("key_{i}");
765 base_obj.insert(key.clone(), Value::String(format!("value_{i}")));
766 ours_obj.insert(
767 key.clone(),
768 if i == 100 {
769 Value::String("modified_by_ours".to_string())
770 } else {
771 Value::String(format!("value_{i}"))
772 },
773 );
774 theirs_obj.insert(
775 key.clone(),
776 if i == 400 {
777 Value::String("modified_by_theirs".to_string())
778 } else {
779 Value::String(format!("value_{i}"))
780 },
781 );
782 }
783
784 let base = serde_json::to_string(&Value::Object(base_obj)).unwrap();
785 let ours = serde_json::to_string(&Value::Object(ours_obj)).unwrap();
786 let theirs = serde_json::to_string(&Value::Object(theirs_obj)).unwrap();
787
788 let result = driver.merge(&base, &ours, &theirs).unwrap();
789 assert!(result.is_some());
790 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
791 assert_eq!(merged["key_100"], "modified_by_ours");
792 assert_eq!(merged["key_400"], "modified_by_theirs");
793 assert_eq!(merged["key_0"], "value_0");
794 assert_eq!(merged["key_499"], "value_499");
795 assert_eq!(merged.as_object().unwrap().len(), 500);
796 }
797
798 #[test]
799 fn test_correctness_null_values() {
800 let driver = JsonDriver::new();
801 let base = r#"{"a": 1, "b": null, "c": "hello"}"#;
802 let ours = r#"{"a": 1, "b": "not_null", "c": "hello"}"#;
803 let theirs = r#"{"a": 10, "b": null, "c": "hello"}"#;
804
805 let result = driver.merge(base, ours, theirs).unwrap();
806 assert!(result.is_some());
807 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
808 assert_eq!(merged["a"], 10, "theirs change should apply");
809 assert_eq!(merged["b"], "not_null", "ours change should apply");
810 assert_eq!(merged["c"], "hello");
811 }
812
813 #[test]
814 fn test_correctness_null_to_value() {
815 let driver = JsonDriver::new();
816 let base = r#"{"key": null}"#;
817 let ours = r#"{"key": null}"#;
818 let theirs = r#"{"key": "now_set"}"#;
819
820 let result = driver.merge(base, ours, theirs).unwrap();
821 assert!(result.is_some());
822 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
823 assert_eq!(merged["key"], "now_set");
824 }
825
826 #[test]
827 fn test_correctness_output_validity() {
828 let driver = JsonDriver::new();
829 let base = r#"{"a": 1, "b": {"c": [1, 2, 3]}}"#;
830 let ours = r#"{"a": 10, "b": {"c": [1, 2, 3]}}"#;
831 let theirs = r#"{"a": 1, "b": {"c": [1, 2, 3], "d": "new"}}"#;
832
833 let result = driver.merge(base, ours, theirs).unwrap();
834 assert!(result.is_some());
835 let merged_str = result.unwrap();
836 let merged: Value = serde_json::from_str(&merged_str)
837 .unwrap_or_else(|e| panic!("merged output should be valid JSON: {e}"));
838 assert_eq!(merged["a"], 10);
839 assert_eq!(merged["b"]["d"], "new");
840 }
841
842 #[test]
843 fn test_correctness_array_merge_positional() {
844 let driver = JsonDriver::new();
845 let base = r#"{"items": [1, 2, 3, 4, 5]}"#;
846 let ours = r#"{"items": [10, 2, 3, 4, 5]}"#;
847 let theirs = r#"{"items": [1, 2, 3, 4, 50]}"#;
848
849 let result = driver.merge(base, ours, theirs).unwrap();
850 assert!(result.is_some());
851 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
852 assert_eq!(merged["items"][0], 10);
853 assert_eq!(merged["items"][1], 2);
854 assert_eq!(merged["items"][4], 50);
855 assert_eq!(merged["items"].as_array().unwrap().len(), 5);
856 }
857
858 #[test]
859 fn test_correctness_array_both_append() {
860 let driver = JsonDriver::new();
861 let base = r#"{"items": [1, 2]}"#;
862 let ours = r#"{"items": [1, 2, 3]}"#;
863 let theirs = r#"{"items": [1, 2, 3, 4]}"#;
864
865 let result = driver.merge(base, ours, theirs).unwrap();
866 assert!(result.is_some());
867 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
868 let arr = merged["items"].as_array().unwrap();
869 assert_eq!(arr.len(), 4);
870 assert_eq!(arr[2], 3);
871 assert_eq!(arr[3], 4);
872 }
873
874 #[test]
875 fn test_correctness_array_both_append_different() {
876 let driver = JsonDriver::new();
877 let base = r#"{"items": [1]}"#;
878 let ours = r#"{"items": [1, 2]}"#;
879 let theirs = r#"{"items": [1, 3]}"#;
880
881 let result = driver.merge(base, ours, theirs).unwrap();
882 assert!(
883 result.is_none(),
884 "both appending different values at same index should conflict"
885 );
886 }
887
888 #[test]
889 fn test_correctness_array_nested_objects() {
890 let driver = JsonDriver::new();
891 let base = r#"{"items": [{"a": 1}, {"a": 2}]}"#;
892 let ours = r#"{"items": [{"a": 10}, {"a": 2}]}"#;
893 let theirs = r#"{"items": [{"a": 1}, {"a": 20}]}"#;
894
895 let result = driver.merge(base, ours, theirs).unwrap();
896 assert!(result.is_some());
897 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
898 assert_eq!(merged["items"][0]["a"], 10);
899 assert_eq!(merged["items"][1]["a"], 20);
900 }
901
902 #[test]
903 fn test_correctness_number_precision() {
904 let driver = JsonDriver::new();
905 let base = r#"{"value": 1}"#;
906 let ours = r#"{"value": 1.0}"#;
907 let theirs = r#"{"value": 1}"#;
908
909 let result = driver.merge(base, ours, theirs).unwrap();
910 assert!(result.is_some());
911 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
912 assert_eq!(merged["value"], 1.0);
913 }
914
915 #[test]
916 fn test_correctness_boolean_merge() {
917 let driver = JsonDriver::new();
918 let base = r#"{"a": true, "b": false}"#;
919 let ours = r#"{"a": false, "b": false}"#;
920 let theirs = r#"{"a": true, "b": true}"#;
921
922 let result = driver.merge(base, ours, theirs).unwrap();
923 assert!(result.is_some());
924 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
925 assert_eq!(merged["a"], false, "ours change to false should apply");
926 assert_eq!(merged["b"], true, "theirs change to true should apply");
927 }
928
929 #[test]
930 fn test_correctness_nested_object_3_levels_deep() {
931 let driver = JsonDriver::new();
932 let base = r#"{"l1": {"l2": {"l3": {"x": 0, "y": 0, "z": 0}}}}"#;
933 let ours = r#"{"l1": {"l2": {"l3": {"x": 1, "y": 0, "z": 0}}}}"#;
934 let theirs = r#"{"l1": {"l2": {"l3": {"x": 0, "y": 0, "z": 1}}}}"#;
935
936 let result = driver.merge(base, ours, theirs).unwrap();
937 assert!(result.is_some());
938 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
939 assert_eq!(merged["l1"]["l2"]["l3"]["x"], 1);
940 assert_eq!(merged["l1"]["l2"]["l3"]["y"], 0);
941 assert_eq!(merged["l1"]["l2"]["l3"]["z"], 1);
942 }
943
944 #[test]
945 fn test_correctness_key_deletion_by_ours() {
946 let driver = JsonDriver::new();
947 let base = r#"{"a": 1, "b": 2, "c": 3}"#;
948 let ours = r#"{"a": 1, "c": 3}"#;
949 let theirs = r#"{"a": 1, "b": 2, "c": 3}"#;
950
951 let result = driver.merge(base, ours, theirs).unwrap();
952 assert!(result.is_some());
953 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
954 assert!(
955 merged.as_object().unwrap().contains_key("b"),
956 "theirs kept 'b' since ours deleted it but theirs didn't"
957 );
958 }
959
960 #[test]
961 fn test_correctness_key_deletion_by_both() {
962 let driver = JsonDriver::new();
963 let base = r#"{"a": 1, "b": 2, "c": 3}"#;
964 let ours = r#"{"a": 1, "c": 3}"#;
965 let theirs = r#"{"a": 1, "c": 3}"#;
966
967 let result = driver.merge(base, ours, theirs).unwrap();
968 assert!(result.is_some());
969 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
970 assert!(
971 !merged.as_object().unwrap().contains_key("b"),
972 "both deleted 'b'"
973 );
974 }
975
976 #[test]
977 fn test_correctness_key_deletion_conflict() {
978 let driver = JsonDriver::new();
979 let base = r#"{"a": 1, "b": 2}"#;
980 let ours = r#"{"a": 1}"#;
981 let theirs = r#"{"a": 1, "b": 99}"#;
982
983 let result = driver.merge(base, ours, theirs).unwrap();
984 assert!(
985 result.is_some(),
986 "ours deletes, theirs modifies → theirs wins"
987 );
988 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
989 assert_eq!(
990 merged["b"], 99,
991 "theirs modification is preserved since ours didn't have the key"
992 );
993 }
994
995 #[test]
996 fn test_correctness_empty_objects() {
997 let driver = JsonDriver::new();
998 let base = r#"{}"#;
999 let ours = r#"{"a": 1}"#;
1000 let theirs = r#"{"b": 2}"#;
1001
1002 let result = driver.merge(base, ours, theirs).unwrap();
1003 assert!(result.is_some());
1004 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
1005 assert_eq!(merged["a"], 1);
1006 assert_eq!(merged["b"], 2);
1007 }
1008
1009 #[test]
1010 fn test_correctness_mixed_types_no_conflict() {
1011 let driver = JsonDriver::new();
1012 let base = r#"{"a": 1, "b": "hello", "c": true, "d": [1,2], "e": {"nested": true}}"#;
1013 let ours = r#"{"a": 10, "b": "hello", "c": true, "d": [1,2], "e": {"nested": true}}"#;
1014 let theirs = r#"{"a": 1, "b": "world", "c": false, "d": [1,2], "e": {"nested": true}}"#;
1015
1016 let result = driver.merge(base, ours, theirs).unwrap();
1017 assert!(result.is_some());
1018 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
1019 assert_eq!(merged["a"], 10);
1020 assert_eq!(merged["b"], "world");
1021 assert_eq!(merged["c"], false);
1022 assert_eq!(merged["e"]["nested"], true);
1023 }
1024
1025 #[test]
1026 fn test_correctness_type_change_conflict() {
1027 let driver = JsonDriver::new();
1028 let base = r#"{"key": 42}"#;
1029 let ours = r#"{"key": "string"}"#;
1030 let theirs = r#"{"key": [1,2,3]}"#;
1031
1032 let result = driver.merge(base, ours, theirs).unwrap();
1033 assert!(
1034 result.is_none(),
1035 "both changing type differently should conflict"
1036 );
1037 }
1038
1039 #[test]
1040 fn test_correctness_type_change_one_side() {
1041 let driver = JsonDriver::new();
1042 let base = r#"{"key": 42}"#;
1043 let ours = r#"{"key": 42}"#;
1044 let theirs = r#"{"key": "string"}"#;
1045
1046 let result = driver.merge(base, ours, theirs).unwrap();
1047 assert!(result.is_some());
1048 let merged: Value = serde_json::from_str(&result.unwrap()).unwrap();
1049 assert_eq!(merged["key"], "string");
1050 }
1051}