1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
# test_diff.py -- Tests for diff functionality.
# Copyright (C) 2025 Dulwich contributors
#
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
# General Public License as published by the Free Software Foundation; version 2.0
# or (at your option) any later version. You can redistribute it and/or
# modify it under the terms of either of these two licenses.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# You should have received a copy of the licenses; if not, see
# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
# License, Version 2.0.
#
"""Tests for diff functionality."""
import io
import unittest
from dulwich.diff import ColorizedDiffStream
from . import TestCase
class ColorizedDiffStreamTests(TestCase):
"""Tests for ColorizedDiffStream."""
def setUp(self):
super().setUp()
self.output = io.BytesIO()
@unittest.skipUnless(
ColorizedDiffStream.is_available(), "Rich not available for colorization"
)
def test_write_simple_diff(self):
"""Test writing a simple diff with colorization."""
stream = ColorizedDiffStream(self.output)
diff_content = b"""--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,3 @@
unchanged line
-removed line
+added line
another unchanged line
"""
stream.write(diff_content)
stream.flush()
# We can't easily test the exact colored output without mocking Rich,
# but we can test that the stream writes something and doesn't crash
result = self.output.getvalue()
self.assertGreater(len(result), 0)
@unittest.skipUnless(
ColorizedDiffStream.is_available(), "Rich not available for colorization"
)
def test_write_line_by_line(self):
"""Test writing diff content line by line."""
stream = ColorizedDiffStream(self.output)
lines = [
b"--- a/file.txt\n",
b"+++ b/file.txt\n",
b"@@ -1,2 +1,2 @@\n",
b"-old line\n",
b"+new line\n",
]
for line in lines:
stream.write(line)
stream.flush()
result = self.output.getvalue()
self.assertGreater(len(result), 0)
@unittest.skipUnless(
ColorizedDiffStream.is_available(), "Rich not available for colorization"
)
def test_writelines(self):
"""Test writelines method."""
stream = ColorizedDiffStream(self.output)
lines = [
b"--- a/file.txt\n",
b"+++ b/file.txt\n",
b"@@ -1,1 +1,1 @@\n",
b"-old\n",
b"+new\n",
]
stream.writelines(lines)
stream.flush()
result = self.output.getvalue()
self.assertGreater(len(result), 0)
@unittest.skipUnless(
ColorizedDiffStream.is_available(), "Rich not available for colorization"
)
def test_partial_line_buffering(self):
"""Test that partial lines are buffered correctly."""
stream = ColorizedDiffStream(self.output)
# Write partial line
stream.write(b"+partial")
# Output should be empty as line is not complete
result = self.output.getvalue()
self.assertEqual(len(result), 0)
# Complete the line
stream.write(b" line\n")
result = self.output.getvalue()
self.assertGreater(len(result), 0)
@unittest.skipUnless(
ColorizedDiffStream.is_available(), "Rich not available for colorization"
)
def test_unicode_handling(self):
"""Test handling of unicode content in diffs."""
stream = ColorizedDiffStream(self.output)
# UTF-8 encoded content
unicode_diff = "--- a/ünïcödë.txt\n+++ b/ünïcödë.txt\n@@ -1,1 +1,1 @@\n-ōld\n+nëw\n".encode()
stream.write(unicode_diff)
stream.flush()
result = self.output.getvalue()
self.assertGreater(len(result), 0)
def test_is_available_static_method(self):
"""Test is_available static method."""
# This should not raise an error regardless of Rich availability
result = ColorizedDiffStream.is_available()
self.assertIsInstance(result, bool)
@unittest.skipIf(
ColorizedDiffStream.is_available(), "Rich is available, skipping fallback test"
)
def test_rich_not_available(self):
"""Test behavior when Rich is not available."""
# When Rich is not available, we can't instantiate ColorizedDiffStream
# This test only runs when Rich is not available
with self.assertRaises(ImportError):
ColorizedDiffStream(self.output)
class MockColorizedDiffStreamTests(TestCase):
"""Tests for ColorizedDiffStream using a mock when Rich is not available."""
def setUp(self):
super().setUp()
self.output = io.BytesIO()
def test_fallback_behavior_with_mock(self):
"""Test that we can handle cases where Rich is not available."""
# This test demonstrates how the CLI handles the case where Rich is unavailable
if not ColorizedDiffStream.is_available():
# When Rich is not available, we should use the raw stream
stream = self.output
else:
# When Rich is available, we can use ColorizedDiffStream
stream = ColorizedDiffStream(self.output)
diff_content = b"+added line\n-removed line\n"
if hasattr(stream, "write"):
stream.write(diff_content)
if hasattr(stream, "flush"):
stream.flush()
# Test that some output was produced
result = self.output.getvalue()
self.assertGreaterEqual(len(result), 0)
|