@@ -28,6 +28,9 @@ pub const Diff = struct {
2828 });
2929 }
3030
31+ pub fn init (operation : Operation , text : []const u8 ) Diff {
32+ return .{ .operation = operation , .text = text };
33+ }
3134 pub fn eql (a : Diff , b : Diff ) bool {
3235 return a .operation == b .operation and std .mem .eql (u8 , a .text , b .text );
3336 }
@@ -1420,3 +1423,128 @@ test diffCharsToLines {
14201423
14211424 // TODO: Implement exhaustive tests
14221425}
1426+
1427+ fn rebuildtexts (allocator : std.mem.Allocator , diffs : std .ArrayListUnmanaged (Diff )) ! [2 ][]const u8 {
1428+ var text = [2 ]std .ArrayList (u8 ){
1429+ std .ArrayList (u8 ).init (allocator ),
1430+ std .ArrayList (u8 ).init (allocator ),
1431+ };
1432+
1433+ for (diffs .items ) | myDiff | {
1434+ if (myDiff .operation != .insert ) {
1435+ try text [0 ].appendSlice (myDiff .text );
1436+ }
1437+ if (myDiff .operation != .delete ) {
1438+ try text [1 ].appendSlice (myDiff .text );
1439+ }
1440+ }
1441+ return .{
1442+ try text [0 ].toOwnedSlice (),
1443+ try text [1 ].toOwnedSlice (),
1444+ };
1445+ }
1446+
1447+ const talloc = std .testing .allocator ;
1448+ test diff {
1449+ // Perform a trivial diff.
1450+ var diffs = std .ArrayListUnmanaged (Diff ){};
1451+ defer diffs .deinit (talloc );
1452+ var this = DiffMatchPatch {};
1453+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "" , "" , false )); // diff: Null case.
1454+
1455+ diffs .items .len = 0 ;
1456+ try diffs .appendSlice (talloc , &.{Diff .init (.equal , "abc" )});
1457+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "abc" , "abc" , false )); // diff: Equality.
1458+
1459+ diffs .items .len = 0 ;
1460+ try diffs .appendSlice (talloc , &.{ Diff .init (.equal , "ab" ), Diff .init (.insert , "123" ), Diff .init (.equal , "c" ) });
1461+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "abc" , "ab123c" , false )); // diff: Simple insertion.
1462+
1463+ diffs .items .len = 0 ;
1464+ try diffs .appendSlice (talloc , &.{ Diff .init (.equal , "a" ), Diff .init (.delete , "123" ), Diff .init (.equal , "bc" ) });
1465+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "a123bc" , "abc" , false )); // diff: Simple deletion.
1466+
1467+ diffs .items .len = 0 ;
1468+ try diffs .appendSlice (talloc , &.{ Diff .init (.equal , "a" ), Diff .init (.insert , "123" ), Diff .init (.equal , "b" ), Diff .init (.insert , "456" ), Diff .init (.equal , "c" ) });
1469+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "abc" , "a123b456c" , false )); // diff: Two insertions.
1470+
1471+ diffs .items .len = 0 ;
1472+ try diffs .appendSlice (talloc , &.{ Diff .init (.equal , "a" ), Diff .init (.delete , "123" ), Diff .init (.equal , "b" ), Diff .init (.delete , "456" ), Diff .init (.equal , "c" ) });
1473+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "a123b456c" , "abc" , false )); // diff: Two deletions.
1474+
1475+ // Perform a real diff.
1476+ // Switch off the timeout.
1477+ this .diff_timeout = 0 ;
1478+ diffs .items .len = 0 ;
1479+ try diffs .appendSlice (talloc , &.{ Diff .init (.delete , "a" ), Diff .init (.insert , "b" ) });
1480+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "a" , "b" , false )); // diff: Simple case #1.
1481+
1482+ diffs .items .len = 0 ;
1483+ try diffs .appendSlice (talloc , &.{ Diff .init (.delete , "Apple" ), Diff .init (.insert , "Banana" ), Diff .init (.equal , "s are a" ), Diff .init (.insert , "lso" ), Diff .init (.equal , " fruit." ) });
1484+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "Apples are a fruit." , "Bananas are also fruit." , false )); // diff: Simple case #2.
1485+
1486+ diffs .items .len = 0 ;
1487+ try diffs .appendSlice (talloc , &.{ Diff .init (.delete , "a" ), Diff .init (.insert , "\u{0680} " ), Diff .init (.equal , "x" ), Diff .init (.delete , "\t " ), Diff .init (.insert , "\x00 " ) });
1488+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "ax\t " , "\u{0680} x\x00 " , false )); // diff: Simple case #3.
1489+
1490+ diffs .items .len = 0 ;
1491+ try diffs .appendSlice (talloc , &.{ Diff .init (.delete , "1" ), Diff .init (.equal , "a" ), Diff .init (.delete , "y" ), Diff .init (.equal , "b" ), Diff .init (.delete , "2" ), Diff .init (.insert , "xab" ) });
1492+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "1ayb2" , "abxab" , false )); // diff: Overlap #1.
1493+
1494+ diffs .items .len = 0 ;
1495+ try diffs .appendSlice (talloc , &.{ Diff .init (.insert , "xaxcx" ), Diff .init (.equal , "abc" ), Diff .init (.delete , "y" ) });
1496+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "abcy" , "xaxcxabc" , false )); // diff: Overlap #2.
1497+
1498+ diffs .items .len = 0 ;
1499+ try diffs .appendSlice (talloc , &.{ Diff .init (.delete , "ABCD" ), Diff .init (.equal , "a" ), Diff .init (.delete , "=" ), Diff .init (.insert , "-" ), Diff .init (.equal , "bcd" ), Diff .init (.delete , "=" ), Diff .init (.insert , "-" ), Diff .init (.equal , "efghijklmnopqrs" ), Diff .init (.delete , "EFGHIJKLMNOefg" ) });
1500+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg" , "a-bcd-efghijklmnopqrs" , false )); // diff: Overlap #3.
1501+
1502+ diffs .items .len = 0 ;
1503+ try diffs .appendSlice (talloc , &.{ Diff .init (.insert , " " ), Diff .init (.equal , "a" ), Diff .init (.insert , "nd" ), Diff .init (.equal , " [[Pennsylvania]]" ), Diff .init (.delete , " and [[New" ) });
1504+ try std .testing .expectEqualDeep (diffs , try this .diff (talloc , "a [[Pennsylvania]] and [[New" , " and [[Pennsylvania]]" , false )); // diff: Large equality.
1505+
1506+ this .diff_timeout = 100 * std .time .ms_per_s ; // 100ms
1507+ // Increase the text lengths by 1024 times to ensure a timeout.
1508+ {
1509+ const a = "`Twas brillig, and the slithy toves\n Did gyre and gimble in the wabe:\n All mimsy were the borogoves,\n And the mome raths outgrabe.\n " ** 10 ;
1510+ const b = "I am the very model of a modern major general,\n I've information vegetable, animal, and mineral,\n I know the kings of England, and I quote the fights historical,\n From Marathon to Waterloo, in order categorical.\n " ** 10 ;
1511+ const start_time = std .time .milliTimestamp ();
1512+ _ = try this .diff (talloc , a , b , false ); // Travis - TODO not sure what the third arg should be
1513+ const end_time = std .time .milliTimestamp ();
1514+ // Test that we took at least the timeout period.
1515+ try std .testing .expect ((this .diff_timeout * 1000 ) * 10000 <= end_time - start_time ); // diff: Timeout min.
1516+ // Test that we didn't take forever (be forgiving).
1517+ // Theoretically this test could fail very occasionally if the
1518+ // OS task swaps or locks up for a second at the wrong moment.
1519+ try std .testing .expect ((this .diff_timeout * 1000 ) * 10000 * 2 > end_time - start_time ); // diff: Timeout max.
1520+ this .diff_timeout = 0 ;
1521+ }
1522+ {
1523+ // Test the linemode speedup.
1524+ // Must be long to pass the 100 char cutoff.
1525+ const a = "1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n " ;
1526+ const b = "abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n abcdefghij\n " ;
1527+ try std .testing .expectEqualDeep (try this .diff (talloc , a , b , true ), try this .diff (talloc , a , b , false )); // diff: Simple line-mode.
1528+ }
1529+ {
1530+ const a = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ;
1531+ const b = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" ;
1532+ try std .testing .expectEqualDeep (try this .diff (talloc , a , b , true ), try this .diff (talloc , a , b , false )); // diff: Single line-mode.
1533+ }
1534+
1535+ const a = "1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n 1234567890\n " ;
1536+ const b = "abcdefghij\n 1234567890\n 1234567890\n 1234567890\n abcdefghij\n 1234567890\n 1234567890\n 1234567890\n abcdefghij\n 1234567890\n 1234567890\n 1234567890\n abcdefghij\n " ;
1537+ const texts_linemode = try rebuildtexts (talloc , try this .diff (talloc , a , b , true ));
1538+ defer {
1539+ talloc .free (texts_linemode [0 ]);
1540+ talloc .free (texts_linemode [1 ]);
1541+ }
1542+ const texts_textmode = try rebuildtexts (talloc , try this .diff (talloc , a , b , false ));
1543+ defer {
1544+ talloc .free (texts_textmode [0 ]);
1545+ talloc .free (texts_textmode [1 ]);
1546+ }
1547+ try std .testing .expectEqualDeep (texts_textmode , texts_linemode ); // diff: Overlap line-mode.
1548+
1549+ // Test null inputs -- not needed because nulls can't be passed in C#.
1550+ }
0 commit comments