)
'
+corrupt_chunk () {
+ graph=full/.git/objects/info/commit-graph &&
+ test_when_finished "rm -rf $graph" &&
+ git -C full commit-graph write --reachable &&
+ corrupt_chunk_file $graph "$@"
+}
+
+check_corrupt_chunk () {
+ corrupt_chunk "$@" &&
+ git -C full -c core.commitGraph=false log >expect.out &&
+ git -C full -c core.commitGraph=true log >out 2>err &&
+ test_cmp expect.out out
+}
+
+test_expect_success 'reader notices too-small oid fanout chunk' '
+ # make it big enough that the graph file is plausible,
+ # otherwise we hit an earlier check
+ check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph oid fanout chunk is wrong size
+ error: commit-graph is missing the OID Fanout chunk
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices fanout/lookup table mismatch' '
+ check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph oid table and fanout disagree on size
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds fanout' '
+ # Rather than try to corrupt a specific hash, we will just
+ # wreck them all. But we cannot just set them all to 0xFFFFFFFF or
+ # similar, as they are used for hi/lo starts in a binary search (so if
+ # they are identical, that indicates that the search should abort
+ # immediately). Instead, we will give them high values that differ by
+ # 2^24, ensuring that any that are used would cause an out-of-bounds
+ # read.
+ check_corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph fanout values out of order
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small commit data chunk' '
+ check_corrupt_chunk CDAT clear 00000000 &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph commit data chunk is wrong size
+ error: commit-graph is missing the Commit Data chunk
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices out-of-bounds extra edge' '
+ check_corrupt_chunk EDGE clear &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph extra-edges pointer out of bounds
+ EOF
+ test_cmp expect.err err
+'
+
+test_expect_success 'reader notices too-small generations chunk' '
+ check_corrupt_chunk GDA2 clear 00000000 &&
+ cat >expect.err <<-\EOF &&
+ error: commit-graph generations chunk is wrong size
+ EOF
+ test_cmp expect.err err
+'
+
+ test_expect_success 'stale commit cannot be parsed when given directly' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit A &&
+ test_commit B &&
+ git commit-graph write --reachable &&
+
+ oid=$(git rev-parse B) &&
+ rm .git/objects/"$(test_oid_to_path "$oid")" &&
+
+ # Verify that it is possible to read the commit from the
+ # commit graph when not being paranoid, ...
+ GIT_COMMIT_GRAPH_PARANOIA=false git rev-list B &&
+ # ... but parsing the commit when double checking that
+ # it actually exists in the object database should fail.
+ test_must_fail git rev-list -1 B
+ )
+ '
+
+ test_expect_success 'stale commit cannot be parsed when traversing graph' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ git commit-graph write --reachable &&
+
+ # Corrupt the repository by deleting the intermediate commit
+ # object. Commands should notice that this object is absent and
+ # thus that the repository is corrupt even if the commit graph
+ # exists.
+ oid=$(git rev-parse B) &&
+ rm .git/objects/"$(test_oid_to_path "$oid")" &&
+
+ # Again, we should be able to parse the commit when not
+ # being paranoid about commit graph staleness...
+ GIT_COMMIT_GRAPH_PARANOIA=false git rev-parse HEAD~2 &&
+ # ... but fail when we are paranoid.
+ test_must_fail git rev-parse HEAD~2 2>error &&
+ grep "error: commit $oid exists in commit-graph but not in the object database" error
+ )
+ '
+
test_done