test_object_format.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # test_object_format.py -- tests for object_format.py
  2. # Copyright (C) 2025 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  5. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  6. # General Public License as published by the Free Software Foundation; version 2.0
  7. # or (at your option) any later version. You can redistribute it and/or
  8. # modify it under the terms of either of these two licenses.
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. # You should have received a copy of the licenses; if not, see
  17. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  18. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  19. # License, Version 2.0.
  20. #
  21. """Tests for object_format module."""
  22. from dulwich.object_format import (
  23. DEFAULT_OBJECT_FORMAT,
  24. OBJECT_FORMAT_TYPE_NUMS,
  25. OBJECT_FORMATS,
  26. SHA1,
  27. SHA256,
  28. get_object_format,
  29. verify_same_object_format,
  30. )
  31. from . import TestCase
  32. class ObjectFormatTests(TestCase):
  33. """Tests for ObjectFormat class."""
  34. def test_sha1_attributes(self) -> None:
  35. """Test SHA1 object format attributes."""
  36. self.assertEqual("sha1", SHA1.name)
  37. self.assertEqual(1, SHA1.type_num)
  38. self.assertEqual(20, SHA1.oid_length)
  39. self.assertEqual(40, SHA1.hex_length)
  40. def test_sha256_attributes(self) -> None:
  41. """Test SHA256 object format attributes."""
  42. self.assertEqual("sha256", SHA256.name)
  43. self.assertEqual(20, SHA256.type_num)
  44. self.assertEqual(32, SHA256.oid_length)
  45. self.assertEqual(64, SHA256.hex_length)
  46. def test_str_representation(self) -> None:
  47. """Test __str__ method returns format name."""
  48. self.assertEqual("sha1", str(SHA1))
  49. self.assertEqual("sha256", str(SHA256))
  50. def test_repr_representation(self) -> None:
  51. """Test __repr__ method."""
  52. self.assertEqual("ObjectFormat('sha1')", repr(SHA1))
  53. self.assertEqual("ObjectFormat('sha256')", repr(SHA256))
  54. def test_new_hash(self) -> None:
  55. """Test new_hash creates a hash object."""
  56. sha1_hash = SHA1.new_hash()
  57. self.assertEqual("sha1", sha1_hash.name)
  58. sha256_hash = SHA256.new_hash()
  59. self.assertEqual("sha256", sha256_hash.name)
  60. def test_hash_object(self) -> None:
  61. """Test hash_object returns binary digest."""
  62. data = b"test data"
  63. # Test SHA1
  64. sha1_digest = SHA1.hash_object(data)
  65. self.assertIsInstance(sha1_digest, bytes)
  66. self.assertEqual(20, len(sha1_digest))
  67. # Verify it matches expected hash
  68. import hashlib
  69. expected_sha1 = hashlib.sha1(data).digest()
  70. self.assertEqual(expected_sha1, sha1_digest)
  71. # Test SHA256
  72. sha256_digest = SHA256.hash_object(data)
  73. self.assertIsInstance(sha256_digest, bytes)
  74. self.assertEqual(32, len(sha256_digest))
  75. expected_sha256 = hashlib.sha256(data).digest()
  76. self.assertEqual(expected_sha256, sha256_digest)
  77. def test_hash_object_hex(self) -> None:
  78. """Test hash_object_hex returns hexadecimal digest."""
  79. data = b"test data"
  80. # Test SHA1
  81. sha1_hex = SHA1.hash_object_hex(data)
  82. self.assertIsInstance(sha1_hex, bytes)
  83. self.assertEqual(40, len(sha1_hex))
  84. # Verify it matches expected hash
  85. import hashlib
  86. expected_sha1_hex = hashlib.sha1(data).hexdigest().encode("ascii")
  87. self.assertEqual(expected_sha1_hex, sha1_hex)
  88. # Test SHA256
  89. sha256_hex = SHA256.hash_object_hex(data)
  90. self.assertIsInstance(sha256_hex, bytes)
  91. self.assertEqual(64, len(sha256_hex))
  92. expected_sha256_hex = hashlib.sha256(data).hexdigest().encode("ascii")
  93. self.assertEqual(expected_sha256_hex, sha256_hex)
  94. class ObjectFormatMappingTests(TestCase):
  95. """Tests for object format mappings."""
  96. def test_object_formats_dict(self) -> None:
  97. """Test OBJECT_FORMATS dictionary."""
  98. self.assertEqual(SHA1, OBJECT_FORMATS["sha1"])
  99. self.assertEqual(SHA256, OBJECT_FORMATS["sha256"])
  100. def test_object_format_type_nums_dict(self) -> None:
  101. """Test OBJECT_FORMAT_TYPE_NUMS dictionary."""
  102. self.assertEqual(SHA1, OBJECT_FORMAT_TYPE_NUMS[1])
  103. self.assertEqual(SHA256, OBJECT_FORMAT_TYPE_NUMS[2])
  104. def test_default_object_format(self) -> None:
  105. """Test DEFAULT_OBJECT_FORMAT is SHA1."""
  106. self.assertEqual(SHA1, DEFAULT_OBJECT_FORMAT)
  107. class GetObjectFormatTests(TestCase):
  108. """Tests for get_object_format function."""
  109. def test_get_object_format_none(self) -> None:
  110. """Test get_object_format with None returns default."""
  111. result = get_object_format(None)
  112. self.assertEqual(DEFAULT_OBJECT_FORMAT, result)
  113. def test_get_object_format_sha1(self) -> None:
  114. """Test get_object_format with 'sha1'."""
  115. result = get_object_format("sha1")
  116. self.assertEqual(SHA1, result)
  117. def test_get_object_format_sha256(self) -> None:
  118. """Test get_object_format with 'sha256'."""
  119. result = get_object_format("sha256")
  120. self.assertEqual(SHA256, result)
  121. def test_get_object_format_case_insensitive(self) -> None:
  122. """Test get_object_format is case insensitive."""
  123. self.assertEqual(SHA1, get_object_format("SHA1"))
  124. self.assertEqual(SHA1, get_object_format("Sha1"))
  125. self.assertEqual(SHA256, get_object_format("SHA256"))
  126. self.assertEqual(SHA256, get_object_format("Sha256"))
  127. def test_get_object_format_invalid(self) -> None:
  128. """Test get_object_format with invalid name raises ValueError."""
  129. with self.assertRaises(ValueError) as cm:
  130. get_object_format("md5")
  131. self.assertEqual("Unsupported object format: md5", str(cm.exception))
  132. class VerifySameObjectFormatTests(TestCase):
  133. """Tests for verify_same_object_format function."""
  134. def test_verify_single_format(self) -> None:
  135. """Test verify_same_object_format with single format."""
  136. result = verify_same_object_format(SHA1)
  137. self.assertEqual(SHA1, result)
  138. def test_verify_multiple_same_formats(self) -> None:
  139. """Test verify_same_object_format with multiple same formats."""
  140. result = verify_same_object_format(SHA1, SHA1, SHA1)
  141. self.assertEqual(SHA1, result)
  142. result = verify_same_object_format(SHA256, SHA256)
  143. self.assertEqual(SHA256, result)
  144. def test_verify_no_formats(self) -> None:
  145. """Test verify_same_object_format with no formats raises ValueError."""
  146. with self.assertRaises(ValueError) as cm:
  147. verify_same_object_format()
  148. self.assertEqual(
  149. "At least one object format must be provided", str(cm.exception)
  150. )
  151. def test_verify_different_formats(self) -> None:
  152. """Test verify_same_object_format with different formats raises ValueError."""
  153. with self.assertRaises(ValueError) as cm:
  154. verify_same_object_format(SHA1, SHA256)
  155. self.assertEqual("Object format mismatch: sha1 != sha256", str(cm.exception))
  156. def test_verify_multiple_different_formats(self) -> None:
  157. """Test verify_same_object_format fails on first mismatch."""
  158. with self.assertRaises(ValueError) as cm:
  159. verify_same_object_format(SHA1, SHA1, SHA256, SHA1)
  160. self.assertEqual("Object format mismatch: sha1 != sha256", str(cm.exception))