diff --git a/lib/src/diff.dart b/lib/src/diff.dart index 4841f21..bc02316 100644 --- a/lib/src/diff.dart +++ b/lib/src/diff.dart @@ -4,7 +4,6 @@ import 'package:ffi/ffi.dart'; import 'package:libgit2dart/libgit2dart.dart'; import 'package:libgit2dart/src/bindings/diff.dart' as bindings; import 'package:libgit2dart/src/bindings/libgit2_bindings.dart'; -import 'package:libgit2dart/src/bindings/patch.dart' as patch_bindings; import 'package:libgit2dart/src/util.dart'; class Diff { @@ -602,112 +601,3 @@ final _statsFinalizer = Finalizer>( (pointer) => bindings.statsFree(pointer), ); // coverage:ignore-end - -class DiffHunk { - /// Initializes a new instance of [DiffHunk] class from provided - /// pointers to patch object and diff hunk object in memory and number of - /// lines in hunk. - const DiffHunk( - this._patchPointer, - this._diffHunkPointer, - this.linesCount, - this.index, - ); - - /// Pointer to memory address for allocated diff hunk object. - final Pointer _diffHunkPointer; - - /// Pointer to memory address for allocated patch object. - final Pointer _patchPointer; - - /// Number of total lines in this hunk. - final int linesCount; - - /// Index of this hunk in the patch. - final int index; - - /// Starting line number in 'old file'. - int get oldStart => _diffHunkPointer.ref.old_start; - - /// Number of lines in 'old file'. - int get oldLines => _diffHunkPointer.ref.old_lines; - - /// Starting line number in 'new file'. - int get newStart => _diffHunkPointer.ref.new_start; - - /// Number of lines in 'new file'. - int get newLines => _diffHunkPointer.ref.new_lines; - - /// Header of a hunk. - String get header { - final list = []; - for (var i = 0; i < _diffHunkPointer.ref.header_len; i++) { - list.add(_diffHunkPointer.ref.header[i]); - } - return String.fromCharCodes(list); - } - - /// List of lines in a hunk of a patch. - List get lines { - final lines = []; - for (var i = 0; i < linesCount; i++) { - lines.add( - DiffLine( - patch_bindings.lines( - patchPointer: _patchPointer, - hunkIndex: index, - lineOfHunk: i, - ), - ), - ); - } - return lines; - } - - @override - String toString() { - return 'DiffHunk{linesCount: $linesCount, index: $index, ' - 'oldStart: $oldStart, oldLines: $oldLines, newStart: $newStart, ' - 'newLines: $newLines, header: $header}'; - } -} - -class DiffLine { - /// Initializes a new instance of [DiffLine] class from provided - /// pointer to diff line object in memory. - const DiffLine(this._diffLinePointer); - - /// Pointer to memory address for allocated diff line object. - final Pointer _diffLinePointer; - - /// Type of the line. - GitDiffLine get origin { - return GitDiffLine.values.singleWhere( - (e) => _diffLinePointer.ref.origin == e.value, - ); - } - - /// Line number in old file or -1 for added line. - int get oldLineNumber => _diffLinePointer.ref.old_lineno; - - /// Line number in new file or -1 for deleted line. - int get newLineNumber => _diffLinePointer.ref.new_lineno; - - /// Number of newline characters in content. - int get numLines => _diffLinePointer.ref.num_lines; - - /// Offset in the original file to the content. - int get contentOffset => _diffLinePointer.ref.content_offset; - - /// Content of the diff line. - String get content => _diffLinePointer.ref.content - .cast() - .toDartString(length: _diffLinePointer.ref.content_len); - - @override - String toString() { - return 'DiffLine{oldLineNumber: $oldLineNumber, ' - 'newLineNumber: $newLineNumber, numLines: $numLines, ' - 'contentOffset: $contentOffset, content: $content}'; - } -} diff --git a/lib/src/patch.dart b/lib/src/patch.dart index 1660aa9..7eb6e7a 100644 --- a/lib/src/patch.dart +++ b/lib/src/patch.dart @@ -1,5 +1,6 @@ import 'dart:ffi'; +import 'package:ffi/ffi.dart'; import 'package:libgit2dart/libgit2dart.dart'; import 'package:libgit2dart/src/bindings/libgit2_bindings.dart'; import 'package:libgit2dart/src/bindings/patch.dart' as bindings; @@ -197,14 +198,49 @@ class Patch { final length = bindings.numHunks(_patchPointer); final hunks = []; - for (var i = 0; i < length; i++) { - final hunk = bindings.hunk(patchPointer: _patchPointer, hunkIndex: i); + for (var index = 0; index < length; index++) { + final hunk = bindings.hunk(patchPointer: _patchPointer, hunkIndex: index); + final hunkPointer = hunk['hunk']! as Pointer; + final linesCount = hunk['linesN']! as int; + + final lines = []; + for (var i = 0; i < linesCount; i++) { + final linePointer = bindings.lines( + patchPointer: _patchPointer, + hunkIndex: index, + lineOfHunk: i, + ); + lines.add( + DiffLine._( + origin: GitDiffLine.values.singleWhere( + (e) => linePointer.ref.origin == e.value, + ), + oldLineNumber: linePointer.ref.old_lineno, + newLineNumber: linePointer.ref.new_lineno, + numLines: linePointer.ref.num_lines, + contentOffset: linePointer.ref.content_offset, + content: linePointer.ref.content + .cast() + .toDartString(length: linePointer.ref.content_len), + ), + ); + } + + final intHeader = []; + for (var i = 0; i < hunkPointer.ref.header_len; i++) { + intHeader.add(hunkPointer.ref.header[i]); + } + hunks.add( - DiffHunk( - _patchPointer, - hunk['hunk']! as Pointer, - hunk['linesN']! as int, - i, + DiffHunk._( + linesCount: linesCount, + index: index, + oldStart: hunkPointer.ref.old_start, + oldLines: hunkPointer.ref.old_lines, + newStart: hunkPointer.ref.new_start, + newLines: hunkPointer.ref.new_lines, + header: String.fromCharCodes(intHeader), + lines: lines, ), ); } @@ -251,3 +287,83 @@ class PatchStats { 'deletions: $deletions}'; } } + +class DiffHunk { + const DiffHunk._({ + required this.linesCount, + required this.index, + required this.oldStart, + required this.oldLines, + required this.newStart, + required this.newLines, + required this.header, + required this.lines, + }); + + /// Number of total lines in this hunk. + final int linesCount; + + /// Index of this hunk in the patch. + final int index; + + /// Starting line number in 'old file'. + final int oldStart; + + /// Number of lines in 'old file'. + final int oldLines; + + /// Starting line number in 'new file'. + final int newStart; + + /// Number of lines in 'new file'. + final int newLines; + + /// Header of a hunk. + final String header; + + /// List of lines in a hunk of a patch. + final List lines; + + @override + String toString() { + return 'DiffHunk{linesCount: $linesCount, index: $index, ' + 'oldStart: $oldStart, oldLines: $oldLines, newStart: $newStart, ' + 'newLines: $newLines, header: $header}'; + } +} + +class DiffLine { + const DiffLine._({ + required this.origin, + required this.oldLineNumber, + required this.newLineNumber, + required this.numLines, + required this.contentOffset, + required this.content, + }); + + /// Type of the line. + final GitDiffLine origin; + + /// Line number in old file or -1 for added line. + final int oldLineNumber; + + /// Line number in new file or -1 for deleted line. + final int newLineNumber; + + /// Number of newline characters in content. + final int numLines; + + /// Offset in the original file to the content. + final int contentOffset; + + /// Content of the diff line. + final String content; + + @override + String toString() { + return 'DiffLine{oldLineNumber: $oldLineNumber, ' + 'newLineNumber: $newLineNumber, numLines: $numLines, ' + 'contentOffset: $contentOffset, content: $content}'; + } +} diff --git a/test/diff_test.dart b/test/diff_test.dart index 754b74e..3ee7afc 100644 --- a/test/diff_test.dart +++ b/test/diff_test.dart @@ -559,33 +559,6 @@ index e69de29..c217c63 100644 expect(Diff.parse(patchText).patch, patchText); }); - test('returns hunks in a patch', () { - final patch = Patch.fromDiff(diff: Diff.parse(patchText), index: 0); - final hunk = patch.hunks[0]; - - expect(patch.hunks.length, 1); - expect(hunk.linesCount, 1); - expect(hunk.oldStart, 0); - expect(hunk.oldLines, 0); - expect(hunk.newStart, 1); - expect(hunk.newLines, 1); - expect(hunk.header, '@@ -0,0 +1 @@\n'); - }); - - test('returns lines in a hunk', () { - final patch = Patch.fromDiff(diff: Diff.parse(patchText), index: 0); - final hunk = patch.hunks[0]; - final line = hunk.lines[0]; - - expect(hunk.lines.length, 1); - expect(line.origin, GitDiffLine.addition); - expect(line.oldLineNumber, -1); - expect(line.newLineNumber, 1); - expect(line.numLines, 1); - expect(line.contentOffset, 155); - expect(line.content, 'Modified content\n'); - }); - test('manually releases allocated memory', () { final diff = Diff.parse(patchText); expect(() => diff.free(), returnsNormally); @@ -597,8 +570,8 @@ index e69de29..c217c63 100644 }); test( - 'returns string representation of Diff, DiffDelta, DiffFile, ' - 'DiffHunk, DiffLine and DiffStats objects', () { + 'returns string representation of Diff, DiffDelta, DiffFile ' + ' and DiffStats objects', () { final diff = Diff.parse(patchText); final patch = Patch.fromDiff(diff: diff, index: 0); final stats = diff.stats; @@ -606,8 +579,6 @@ index e69de29..c217c63 100644 expect(diff.toString(), contains('Diff{')); expect(patch.delta.toString(), contains('DiffDelta{')); expect(patch.delta.oldFile.toString(), contains('DiffFile{')); - expect(patch.hunks[0].toString(), contains('DiffHunk{')); - expect(patch.hunks[0].lines[0].toString(), contains('DiffLine{')); expect(stats.toString(), contains('DiffStats{')); }); }); diff --git a/test/patch_test.dart b/test/patch_test.dart index 8ffd7df..7e222e4 100644 --- a/test/patch_test.dart +++ b/test/patch_test.dart @@ -155,6 +155,43 @@ index e69de29..0000000 expect(() => Patch(nullptr).text, throwsA(isA())); }); + test('returns hunks in a patch', () { + final patch = Patch.fromBuffers( + oldBuffer: oldBuffer, + newBuffer: newBuffer, + oldBufferPath: path, + newBufferPath: path, + ); + final hunk = patch.hunks[0]; + + expect(patch.hunks.length, 1); + expect(hunk.linesCount, 1); + expect(hunk.oldStart, 0); + expect(hunk.oldLines, 0); + expect(hunk.newStart, 1); + expect(hunk.newLines, 1); + expect(hunk.header, '@@ -0,0 +1 @@\n'); + }); + + test('returns lines in a hunk', () { + final patch = Patch.fromBuffers( + oldBuffer: oldBuffer, + newBuffer: newBuffer, + oldBufferPath: path, + newBufferPath: path, + ); + final hunk = patch.hunks[0]; + final line = hunk.lines[0]; + + expect(hunk.lines.length, 1); + expect(line.origin, GitDiffLine.addition); + expect(line.oldLineNumber, -1); + expect(line.newLineNumber, 1); + expect(line.numLines, 1); + expect(line.contentOffset, 0); + expect(line.content, 'Feature edit\n'); + }); + test('returns line counts of each type in a patch', () { final patch = Patch.fromBuffers( oldBuffer: oldBuffer, @@ -180,7 +217,9 @@ index e69de29..0000000 expect(() => patch.free(), returnsNormally); }); - test('returns string representation of Patch object', () { + test( + 'returns string representation of Patch, DiffHunk and DiffLine objects', + () { final patch = Patch.fromBuffers( oldBuffer: oldBuffer, newBuffer: newBuffer, @@ -189,6 +228,8 @@ index e69de29..0000000 ); expect(patch.toString(), contains('Patch{')); + expect(patch.hunks[0].toString(), contains('DiffHunk{')); + expect(patch.hunks[0].lines[0].toString(), contains('DiffLine{')); }); }); }