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