# test_sha256.py -- Tests for SHA256 support # Copyright (C) 2024 The 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 public 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 # for a copy of the GNU General Public License # and for a copy of the Apache # License, Version 2.0. # """Tests for SHA256 support in Dulwich.""" import os import shutil import tempfile import unittest from dulwich.object_format import SHA1, SHA256, get_object_format from dulwich.objects import Blob, Tree, valid_hexsha from dulwich.repo import MemoryRepo, Repo class HashAlgorithmTests(unittest.TestCase): """Tests for the hash algorithm abstraction.""" def test_sha1_properties(self): """Test SHA1 algorithm properties.""" alg = SHA1 self.assertEqual(alg.name, "sha1") self.assertEqual(alg.oid_length, 20) self.assertEqual(alg.hex_length, 40) def test_sha256_properties(self): """Test SHA256 algorithm properties.""" alg = SHA256 self.assertEqual(alg.name, "sha256") self.assertEqual(alg.oid_length, 32) self.assertEqual(alg.hex_length, 64) def test_get_hash_algorithm(self): """Test getting hash algorithms by name.""" self.assertEqual(get_object_format("sha1"), SHA1) self.assertEqual(get_object_format("sha256"), SHA256) self.assertEqual(get_object_format(None), SHA1) # Default with self.assertRaises(ValueError): get_object_format("invalid") class ObjectHashingTests(unittest.TestCase): """Tests for object hashing with different algorithms.""" def test_blob_sha1(self): """Test blob hashing with SHA1.""" blob = Blob() blob.data = b"Hello, World!" # Default should be SHA1 sha1_id = blob.id self.assertEqual(len(sha1_id), 40) self.assertTrue(valid_hexsha(sha1_id)) def test_blob_sha256(self): """Test blob hashing with SHA256.""" blob = Blob() blob.data = b"Hello, World!" # Get SHA256 hash sha256_id = blob.get_id(SHA256) self.assertEqual(len(sha256_id), 64) self.assertTrue(valid_hexsha(sha256_id)) # SHA256 ID should be different from SHA1 sha1_id = blob.id self.assertNotEqual(sha1_id, sha256_id) # Verify .id property returns SHA1 for backward compatibility self.assertEqual(blob.id, sha1_id) self.assertEqual(blob.get_id(), sha1_id) # Default should be SHA1 def test_tree_sha256(self): """Test tree hashing with SHA256.""" tree = Tree() tree.add(b"file.txt", 0o100644, b"a" * 40) # SHA1 hex # Get SHA1 (default) sha1_id = tree.id self.assertEqual(len(sha1_id), 40) # Get SHA256 sha256_id = tree.get_id(SHA256) self.assertEqual(len(sha256_id), 64) # Verify they're different self.assertNotEqual(sha1_id, sha256_id) def test_valid_hexsha(self): """Test hex SHA validation for both algorithms.""" # Valid SHA1 self.assertTrue(valid_hexsha(b"1234567890abcdef1234567890abcdef12345678")) # Valid SHA256 self.assertTrue( valid_hexsha( b"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" ) ) # Invalid lengths self.assertFalse(valid_hexsha(b"1234")) self.assertFalse( valid_hexsha(b"1234567890abcdef1234567890abcdef123456") ) # 38 chars # Invalid characters self.assertFalse(valid_hexsha(b"123456789gabcdef1234567890abcdef12345678")) class RepositorySHA256Tests(unittest.TestCase): """Tests for SHA256 repository support.""" def setUp(self): """Set up test repository directory.""" self.test_dir = tempfile.mkdtemp() def tearDown(self): """Clean up test repository.""" shutil.rmtree(self.test_dir) def test_init_sha256_repo(self): """Test initializing a SHA256 repository.""" repo_path = os.path.join(self.test_dir, "sha256_repo") repo = Repo.init(repo_path, mkdir=True, object_format="sha256") # Check repository format version config = repo.get_config() self.assertEqual(config.get(("core",), "repositoryformatversion"), b"1") # Check object format extension self.assertEqual(config.get(("extensions",), "objectformat"), b"sha256") # Check hash algorithm detection self.assertEqual(repo.object_format, SHA256) repo.close() def test_init_sha1_repo(self): """Test initializing a SHA1 repository (default).""" repo_path = os.path.join(self.test_dir, "sha1_repo") repo = Repo.init(repo_path, mkdir=True) # Check repository format version config = repo.get_config() self.assertEqual(config.get(("core",), "repositoryformatversion"), b"0") # Object format extension should not exist with self.assertRaises(KeyError): config.get(("extensions",), "objectformat") # Check hash algorithm detection self.assertEqual(repo.object_format, SHA1) repo.close() def test_format_version_validation(self): """Test format version validation for SHA256.""" repo_path = os.path.join(self.test_dir, "invalid_repo") # SHA256 with format version 0 should fail with self.assertRaises(ValueError) as cm: Repo.init(repo_path, mkdir=True, format=0, object_format="sha256") self.assertIn("SHA256", str(cm.exception)) def test_memory_repo_sha256(self): """Test SHA256 support in memory repository.""" repo = MemoryRepo.init_bare([], {}, object_format="sha256") # Check hash algorithm self.assertEqual(repo.object_format, SHA256) if __name__ == "__main__": unittest.main()