1# Copyright 2010-2021 The pygit2 contributors
2#
3# This file is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License, version 2,
5# as published by the Free Software Foundation.
6#
7# In addition to the permissions in the GNU General Public License,
8# the authors give you unlimited permission to link the compiled
9# version of this file into combinations with other programs,
10# and to distribute those combinations without any restriction
11# coming from the use of this file.  (The General Public License
12# restrictions do apply in other respects; for example, they cover
13# modification of the file, and distribution when not linked into
14# a combined executable.)
15#
16# This file is distributed in the hope that it will be useful, but
17# WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19# General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; see the file COPYING.  If not, write to
23# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24# Boston, MA 02110-1301, USA.
25
26"""Tests for Index files."""
27
28import os
29from pathlib import Path
30
31import pytest
32
33import pygit2
34from pygit2 import Repository, Index, Oid
35from . import utils
36
37
38def test_bare(barerepo):
39    assert len(barerepo.index) == 0
40
41
42def test_index(testrepo):
43    assert testrepo.index is not None
44
45def test_read(testrepo):
46    index = testrepo.index
47    assert len(index) == 2
48
49    with pytest.raises(TypeError): index[()]
50    utils.assertRaisesWithArg(ValueError, -4, lambda: index[-4])
51    utils.assertRaisesWithArg(KeyError, 'abc', lambda: index['abc'])
52
53    sha = 'a520c24d85fbfc815d385957eed41406ca5a860b'
54    assert 'hello.txt' in index
55    assert index['hello.txt'].hex == sha
56    assert index['hello.txt'].path == 'hello.txt'
57    assert index[1].hex == sha
58
59def test_add(testrepo):
60    index = testrepo.index
61
62    sha = '0907563af06c7464d62a70cdd135a6ba7d2b41d8'
63    assert 'bye.txt' not in index
64    index.add('bye.txt')
65    assert 'bye.txt' in index
66    assert len(index) == 3
67    assert index['bye.txt'].hex == sha
68
69def test_add_aspath(testrepo):
70    index = testrepo.index
71
72    assert 'bye.txt' not in index
73    index.add(Path('bye.txt'))
74    assert 'bye.txt' in index
75
76def test_add_all(testrepo):
77    clear(testrepo)
78
79    sha_bye = '0907563af06c7464d62a70cdd135a6ba7d2b41d8'
80    sha_hello = 'a520c24d85fbfc815d385957eed41406ca5a860b'
81
82    index = testrepo.index
83    index.add_all(['*.txt'])
84
85    assert 'bye.txt' in index
86    assert 'hello.txt' in index
87
88    assert index['bye.txt'].hex == sha_bye
89    assert index['hello.txt'].hex == sha_hello
90
91    clear(testrepo)
92
93    index.add_all(['bye.t??', 'hello.*'])
94    assert 'bye.txt' in index
95    assert 'hello.txt' in index
96
97    assert index['bye.txt'].hex == sha_bye
98    assert index['hello.txt'].hex == sha_hello
99
100    clear(testrepo)
101
102    index.add_all(['[byehlo]*.txt'])
103    assert 'bye.txt' in index
104    assert 'hello.txt' in index
105
106    assert index['bye.txt'].hex == sha_bye
107    assert index['hello.txt'].hex == sha_hello
108
109def test_add_all_aspath(testrepo):
110    clear(testrepo)
111
112    index = testrepo.index
113    index.add_all([Path('bye.txt'), Path('hello.txt')])
114    assert 'bye.txt' in index
115    assert 'hello.txt' in index
116
117def clear(repo):
118    index = repo.index
119    assert len(index) == 2
120    index.clear()
121    assert len(index) == 0
122
123def test_write(testrepo):
124    index = testrepo.index
125    index.add('bye.txt')
126    index.write()
127
128    index.clear()
129    assert 'bye.txt' not in index
130    index.read()
131    assert 'bye.txt' in index
132
133
134def test_read_tree(testrepo):
135    tree_oid = '68aba62e560c0ebc3396e8ae9335232cd93a3f60'
136    # Test reading first tree
137    index = testrepo.index
138    assert len(index) == 2
139    index.read_tree(tree_oid)
140    assert len(index) == 1
141    # Test read-write returns the same oid
142    oid = index.write_tree()
143    assert oid.hex == tree_oid
144    # Test the index is only modified in memory
145    index.read()
146    assert len(index) == 2
147
148
149def test_write_tree(testrepo):
150    oid = testrepo.index.write_tree()
151    assert oid.hex == 'fd937514cb799514d4b81bb24c5fcfeb6472b245'
152
153def test_iter(testrepo):
154    index = testrepo.index
155    n = len(index)
156    assert len(list(index)) == n
157
158    # Compare SHAs, not IndexEntry object identity
159    entries = [index[x].hex for x in range(n)]
160    assert list(x.hex for x in index) == entries
161
162def test_mode(testrepo):
163    """
164        Testing that we can access an index entry mode.
165    """
166    index = testrepo.index
167
168    hello_mode = index['hello.txt'].mode
169    assert hello_mode == 33188
170
171def test_bare_index(testrepo):
172    index = pygit2.Index(os.path.join(testrepo.path, 'index'))
173    assert [x.hex for x in index] == [x.hex for x in testrepo.index]
174
175    with pytest.raises(pygit2.GitError): index.add('bye.txt')
176
177def test_remove(testrepo):
178    index = testrepo.index
179    assert 'hello.txt' in index
180    index.remove('hello.txt')
181    assert 'hello.txt' not in index
182
183def test_remove_all(testrepo):
184    index = testrepo.index
185    assert 'hello.txt' in index
186    index.remove_all(['*.txt'])
187    assert 'hello.txt' not in index
188
189    index.remove_all(['not-existing'])  # this doesn't error
190
191def test_remove_aspath(testrepo):
192    index = testrepo.index
193    assert 'hello.txt' in index
194    index.remove(Path('hello.txt'))
195    assert 'hello.txt' not in index
196
197def test_remove_all_aspath(testrepo):
198    index = testrepo.index
199    assert 'hello.txt' in index
200    index.remove_all([Path('hello.txt')])
201    assert 'hello.txt' not in index
202
203def test_change_attributes(testrepo):
204    index = testrepo.index
205    entry = index['hello.txt']
206    ign_entry = index['.gitignore']
207    assert ign_entry.id != entry.id
208    assert entry.mode != pygit2.GIT_FILEMODE_BLOB_EXECUTABLE
209    entry.path = 'foo.txt'
210    entry.id = ign_entry.id
211    entry.mode = pygit2.GIT_FILEMODE_BLOB_EXECUTABLE
212    assert 'foo.txt' == entry.path
213    assert ign_entry.id == entry.id
214    assert pygit2.GIT_FILEMODE_BLOB_EXECUTABLE == entry.mode
215
216def test_write_tree_to(testrepo, tmp_path):
217    pygit2.option(pygit2.GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, False)
218    with utils.TemporaryRepository('emptyrepo.tar', tmp_path) as path:
219        nrepo = Repository(path)
220        id = testrepo.index.write_tree(nrepo)
221        assert nrepo[id] is not None
222
223
224def test_create_entry(testrepo):
225    index = testrepo.index
226    hello_entry = index['hello.txt']
227    entry = pygit2.IndexEntry('README.md', hello_entry.id, hello_entry.mode)
228    index.add(entry)
229    tree_id = index.write_tree()
230    assert '60e769e57ae1d6a2ab75d8d253139e6260e1f912' == str(tree_id)
231
232def test_create_entry_aspath(testrepo):
233    index = testrepo.index
234    hello_entry = index[Path('hello.txt')]
235    entry = pygit2.IndexEntry(Path('README.md'), hello_entry.id, hello_entry.mode)
236    index.add(entry)
237    index.write_tree()
238
239def test_entry_eq(testrepo):
240    index = testrepo.index
241    hello_entry = index['hello.txt']
242    entry = pygit2.IndexEntry(hello_entry.path, hello_entry.id, hello_entry.mode)
243    assert hello_entry == entry
244
245    entry = pygit2.IndexEntry("README.md", hello_entry.id, hello_entry.mode)
246    assert hello_entry != entry
247    oid = Oid(hex='0907563af06c7464d62a70cdd135a6ba7d2b41d8')
248    entry = pygit2.IndexEntry(hello_entry.path, oid, hello_entry.mode)
249    assert hello_entry != entry
250    entry = pygit2.IndexEntry(hello_entry.path, hello_entry.id, pygit2.GIT_FILEMODE_BLOB_EXECUTABLE)
251    assert hello_entry != entry
252
253def test_entry_repr(testrepo):
254    index = testrepo.index
255    hello_entry = index['hello.txt']
256    assert (repr(hello_entry) ==
257            "<pygit2.index.IndexEntry path=hello.txt id=a520c24d85fbfc815d385957eed41406ca5a860b mode=33188>")
258    assert (str(hello_entry) ==
259            "<path=hello.txt id=a520c24d85fbfc815d385957eed41406ca5a860b mode=33188>")
260
261
262def test_create_empty():
263    Index()
264
265def test_create_empty_read_tree_as_string():
266    index = Index()
267    # no repo associated, so we don't know where to read from
268    with pytest.raises(TypeError):
269        index('read_tree', 'fd937514cb799514d4b81bb24c5fcfeb6472b245')
270
271def test_create_empty_read_tree(testrepo):
272    index = Index()
273    index.read_tree(testrepo['fd937514cb799514d4b81bb24c5fcfeb6472b245'])
274