File: test_set_index.rb

package info (click to toggle)
ruby-git 4.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,564 kB
  • sloc: ruby: 9,983; sh: 519; perl: 64; makefile: 6
file content (167 lines) | stat: -rw-r--r-- 7,790 bytes parent folder | download
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
# frozen_string_literal: true

require 'test_helper'
require 'git'
require 'fileutils'
require 'tmpdir'

# A test case to demonstrate the use of Git::Base#set_index
#
# This test case will to programmatically create a new commit without affecting the
# main working directory or index.
#
class SetIndexTest < Test::Unit::TestCase
  # Set up a temporary Git repository before each test.
  def setup
    # Create a temporary directory for the repository
    @repo_path = Dir.mktmpdir('git_test')

    # Initialize a new Git repository in the temporary directory
    @repo = Git.init(@repo_path, initial_branch: 'main')

    # Change into the repo directory to perform file operations
    Dir.chdir(@repo_path) do
      # Create and commit an initial file to establish a HEAD and a root tree.
      # This gives us a base state to work from.
      File.write('file1.txt', 'This is the first file.')
      @repo.add('file1.txt')
      @repo.commit('Initial commit')
    end
  end

  attr_reader :repo_path, :repo

  # Clean up the temporary repository after each test.
  def teardown
    FileUtils.rm_rf(repo_path)
  end

  # Tests that `set_index` can point to a new, non-existent index file
  # when `must_exist: false` is specified.
  def test_set_index_with_must_exist_false_for_new_path
    custom_index_path = File.join(repo_path, 'custom_index')
    assert(!File.exist?(custom_index_path), 'Precondition: Custom index file should not exist.')

    # Action: Set the index to a new path, allowing it to not exist.
    repo.set_index(custom_index_path, must_exist: false)

    # Verification: The repo object should now point to the new index path.
    assert_equal(custom_index_path, repo.index.to_s, 'Index path should be updated to the custom path.')
  end

  # Tests that `set_index` successfully points to an existing index file
  # when `must_exist: true` is specified.
  def test_set_index_with_must_exist_true_for_existing_path
    original_index_path = repo.index.to_s
    assert(File.exist?(original_index_path), 'Precondition: Original index file should exist.')

    # Action: Set the index to the same, existing path, explicitly requiring it to exist.
    repo.set_index(original_index_path, must_exist: true)

    # Verification: The index path should remain unchanged.
    assert_equal(original_index_path, repo.index.to_s, 'Index path should still be the original path.')
  end

  # Tests that `set_index` raises an ArgumentError when trying to point to a
  # non-existent index file with the default behavior (`must_exist: true`).
  def test_set_index_with_must_exist_true_raises_error_for_new_path
    non_existent_path = File.join(repo_path, 'no_such_file')
    assert(!File.exist?(non_existent_path), 'Precondition: The target index path should not exist.')

    # Action & Verification: Assert that an ArgumentError is raised.
    assert_raise(ArgumentError, 'Should raise ArgumentError for a non-existent index path.') do
      repo.set_index(non_existent_path) # must_exist defaults to true
    end
  end

  # Tests that using the deprecated `check` argument issues a warning via mocking.
  def test_set_index_with_deprecated_check_argument
    custom_index_path = File.join(repo_path, 'custom_index')
    assert(!File.exist?(custom_index_path), 'Precondition: Custom index file should not exist.')

    # Set up the mock expectation.
    # We expect Git::Deprecation.warn to be called once with a message
    # matching the expected deprecation warning.
    Git::Deprecation.expects(:warn).with(
      regexp_matches(/The "check" argument is deprecated/)
    )

    # Action: Use the deprecated positional argument `check = false`
    repo.set_index(custom_index_path, false)

    # Verification: The repo object should still point to the new index path.
    assert_equal(custom_index_path, repo.index.to_s, 'Index path should be updated even with deprecated argument.')
    # Mocha automatically verifies the expectation at the end of the test.
  end

  # This test demonstrates creating a new commit on a new branch by
  # manipulating a custom, temporary index file. This allows for building
  # commits programmatically without touching the working directory or the
  # default .git/index.
  def test_programmatic_commit_with_set_index
    # 1. Get the initial commit object to use as a parent for our new commit.
    main_commit = repo.gcommit('main')
    assert(!main_commit.nil?, 'Initial commit should exist.')

    # 2. Define a path for a new, temporary index file within the repo directory.
    custom_index_path = File.join(repo_path, 'custom_index')
    assert(!File.exist?(custom_index_path), 'Custom index file should not exist yet.')

    # 3. Point the git object to use our custom index file.
    #    Since the file doesn't exist yet, we must pass `must_exist: false`.
    repo.set_index(custom_index_path, must_exist: false)
    assert_equal(custom_index_path, repo.index.to_s, 'The git object should now be using the custom index.')

    # 4. Populate the new index by reading the tree from our initial commit into it.
    #    This stages all the files from the 'main' commit in our custom index.
    repo.read_tree(main_commit.gtree.sha)

    # 5. Programmatically create a new file blob and add it to our custom index.
    #    This simulates `git add` for a new file, but operates directly on the index.
    new_content = 'This is a brand new file.'
    blob_sha = Tempfile.create('new_blob_content') do |file|
      file.write(new_content)
      file.rewind
      # Use `git hash-object -w` to write the blob to the object database and get its SHA
      repo.lib.send(:command, 'hash-object', '-w', file.path)
    end
    repo.lib.send(:command, 'update-index', '--add', '--cacheinfo', "100644,#{blob_sha},new_file.txt")

    # 6. Write the state of the custom index to a new tree object in the Git database.
    new_tree_sha = repo.write_tree
    assert_match(/^[0-9a-f]{40}$/, new_tree_sha, 'A new tree SHA should be created.')

    # 7. Create a new commit object from the new tree.
    #    This commit will have the initial commit as its parent.
    new_commit = repo.commit_tree(
      new_tree_sha,
      parents: [main_commit.sha],
      message: 'Commit created programmatically via custom index'
    )
    assert(new_commit.commit?, 'A new commit object should be created.')

    # 8. Create a new branch pointing to our new commit.
    repo.branch('feature-branch').update_ref(new_commit)
    assert(repo.branch('feature-branch').gcommit.sha == new_commit.sha, 'feature-branch should point to the new commit.')

    # --- Verification ---
    # Verify the history of the new branch
    feature_log = repo.log.object('feature-branch').execute
    main_commit_sha = repo.rev_parse('main') # Get SHA directly for reliable comparison

    assert_equal(2, feature_log.size, 'Feature branch should have two commits.')
    assert_equal(new_commit.sha, feature_log.first.sha, 'HEAD of feature-branch should be our new commit.')
    assert_equal(main_commit_sha, feature_log.last.sha, 'Parent of new commit should be the initial commit.')

    # Verify that the main branch is unchanged
    main_log = repo.log.object('main').execute
    assert_equal(1, main_log.size, 'Main branch should still have one commit.')
    assert_equal(main_commit_sha, main_log.first.sha, 'Main branch should still point to the initial commit.')

    # Verify the contents of the new commit's tree
    new_commit_tree = new_commit.gtree
    assert(new_commit_tree.blobs.key?('file1.txt'), 'Original file should exist in the new tree.')
    assert(new_commit_tree.blobs.key?('new_file.txt'), 'New file should exist in the new tree.')
    assert_equal(new_content, new_commit_tree.blobs['new_file.txt'].contents, 'Content of new file should match.')
  end
end