From 6ffade20fc886e32f2802a7efd1b9721d575de9f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 May 2025 21:15:52 +0000 Subject: [PATCH 1/2] Initial plan for issue From 8748a3acf3a75b3ece46f6b30fb22080d1d890cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 May 2025 21:20:41 +0000 Subject: [PATCH 2/2] Analyze list insertion/deletion optimization issue in JsonPatch Co-authored-by: stefankoegl <184196+stefankoegl@users.noreply.github.com> --- comprehensive_test.py | 65 +++++++++++++++++++++++++++++++++++++++++++ test_failing.py | 30 ++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 comprehensive_test.py create mode 100644 test_failing.py diff --git a/comprehensive_test.py b/comprehensive_test.py new file mode 100644 index 0000000..d02e3e7 --- /dev/null +++ b/comprehensive_test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import jsonpatch +import json + +class ComprehensiveOptimizationTest(unittest.TestCase): + def test_list_insertion_optimization(self): + """Test that list insertions are optimized correctly.""" + test_cases = [ + # Simple replacements - already work + ( + {'foo': [1, 2, 3]}, + {'foo': [1, 4, 3]}, + "Simple element replacement" + ), + # Insertion and deletion (same index) - should be optimized to replace + ( + [1, 2, 3, 4], + [1, 5, 3, 4], + "Insert and remove at same index - should be replace" + ), + # Insertion at beginning, removal at end - might be optimized to replace + ( + [1, 2, 3, 4], + [5, 1, 2, 3], + "Insert at beginning, remove at end - could be optimized" + ), + # Insert and remove at different positions - harder to optimize + ( + [1, 2, 3, 4], + [1, 5, 2, 4], + "Insert and remove at different positions" + ), + # Multiple changes - complex case + ( + [1, 2, 3, 4, 5], + [1, 6, 2, 7, 5], + "Multiple replacements" + ), + ] + + for src, dst, msg in test_cases: + print(f"\nTesting: {msg}") + print(f"Source: {src}") + print(f"Destination: {dst}") + patch = list(jsonpatch.make_patch(src, dst)) + print(f"Generated patch: {json.dumps(patch, indent=2)}") + # Verify that applying the patch produces the expected result + result = jsonpatch.apply_patch(src, patch) + self.assertEqual(result, dst) + print(f"Result after applying patch: {result}") + + # Count the operations + op_counts = {} + for op in patch: + op_type = op['op'] + op_counts[op_type] = op_counts.get(op_type, 0) + 1 + + print(f"Operation counts: {op_counts}") + print("-" * 50) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test_failing.py b/test_failing.py new file mode 100644 index 0000000..02731d0 --- /dev/null +++ b/test_failing.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import jsonpatch + +class FailingOptimizationTest(unittest.TestCase): + def test_list_replacement_optimization(self): + # A case where a list element is replaced with a new value + src = {'foo': [1, 2, 3]} + dst = {'foo': [1, 4, 3]} + patch = list(jsonpatch.make_patch(src, dst)) + print("Patch:", patch) + self.assertEqual(len(patch), 1) + self.assertEqual(patch[0]['op'], 'replace') + self.assertEqual(patch[0]['path'], '/foo/1') + self.assertEqual(patch[0]['value'], 4) + + def test_list_insertion_deletion(self): + # A case where elements are both inserted and deleted + src = [1, 2, 3, 4] + dst = [1, 5, 2, 4] + patch = list(jsonpatch.make_patch(src, dst)) + print("Insertion/Deletion Patch:", patch) + # Expected: replace operation at index 1 and removal of index 2 + # Instead of producing multiple operations + # The optimization should collapse sequential operations when possible + +if __name__ == "__main__": + unittest.main() \ No newline at end of file