()
| 653 | |
| 654 | #[test] |
| 655 | fn conflict_on_overlapping_edits() { |
| 656 | let mut txn = MockTxn::new(); |
| 657 | let store = MemoryChangeStore::new(); |
| 658 | |
| 659 | // Base: "x = 1" |
| 660 | let base_hash = make_change(&store, b"x = 1"); |
| 661 | let base_id = NodeId::new(1); |
| 662 | txn.register(base_id, base_hash); |
| 663 | |
| 664 | // Left: "x = 2" |
| 665 | let left_hash = make_change(&store, b"x = 2"); |
| 666 | let left_id = NodeId::new(2); |
| 667 | txn.register(left_id, left_hash); |
| 668 | |
| 669 | // Right: "x = 3" |
| 670 | let right_hash = make_change(&store, b"x = 3"); |
| 671 | let right_id = NodeId::new(3); |
| 672 | txn.register(right_id, right_hash); |
| 673 | |
| 674 | let engine = SemanticMergeEngine::new(&txn, &store); |
| 675 | |
| 676 | let v_base = GraphNode::new(base_id, ChangePosition::new(0), ChangePosition::new(5)); |
| 677 | let v_left = GraphNode::new(left_id, ChangePosition::new(0), ChangePosition::new(5)); |
| 678 | let v_right = GraphNode::new(right_id, ChangePosition::new(0), ChangePosition::new(5)); |
| 679 | |
| 680 | let group = ConflictGroup::new(vec![v_left, v_right]).with_ancestor(v_base); |
| 681 | let outcome = engine.try_merge(&group).unwrap(); |
| 682 | |
| 683 | assert!( |
| 684 | outcome.is_conflict(), |
| 685 | "expected Conflict, got {:?}", |
| 686 | outcome, |
| 687 | ); |
| 688 | if let MergeOutcome::Conflict { |
| 689 | base, |
| 690 | left, |
| 691 | right, |
| 692 | left_change, |
| 693 | right_change, |
| 694 | } = &outcome |
| 695 | { |
| 696 | assert_eq!(base, b"x = 1"); |
| 697 | assert_eq!(left, b"x = 2"); |
| 698 | assert_eq!(right, b"x = 3"); |
| 699 | assert_eq!(*left_change, left_id); |
| 700 | assert_eq!(*right_change, right_id); |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | // ---- SemanticMergeEngine: both sides same edit → AutoMerged ----------- |
| 705 |
nothing calls this directly
no test coverage detected