t12-repo.c 15.8 KB
Newer Older
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
/*
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2,
 * as published by the Free Software Foundation.
 *
 * In addition to the permissions in the GNU General Public License,
 * the authors give you unlimited permission to link the compiled
 * version of this file into combinations with other programs,
 * and to distribute those combinations without any restriction
 * coming from the use of this file.  (The General Public License
 * restrictions do apply in other respects; for example, they cover
 * modification of the file, and distribution when not linked into
 * a combined executable.)
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "test_lib.h"
#include "test_helpers.h"

#include "odb.h"
#include "git2/odb_backend.h"
30
#include "repository.h"
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

typedef struct {
	git_odb_backend base;
	int position;
} fake_backend;

git_odb_backend *new_backend(int position)
{
	fake_backend *b;

	b = git__malloc(sizeof(fake_backend));
	if (b == NULL)
		return NULL;

	memset(b, 0x0, sizeof(fake_backend));
	b->position = position;
	return (git_odb_backend *)b;
}

int test_backend_sorting(git_odb *odb)
{
	unsigned int i;

	for (i = 0; i < odb->backends.length; ++i) {
		fake_backend *internal = *((fake_backend **)git_vector_get(&odb->backends, i));

		if (internal == NULL)
			return GIT_ERROR;

		if (internal->position != (int)i)
			return GIT_ERROR;
	}

	return GIT_SUCCESS;
}

67
BEGIN_TEST(odb0, "assure that ODB backends are properly sorted")
68 69 70 71 72 73 74 75 76 77
	git_odb *odb;
	must_pass(git_odb_new(&odb));
	must_pass(git_odb_add_backend(odb, new_backend(0), 5));
	must_pass(git_odb_add_backend(odb, new_backend(2), 3));
	must_pass(git_odb_add_backend(odb, new_backend(1), 4));
	must_pass(git_odb_add_backend(odb, new_backend(3), 1));
	must_pass(test_backend_sorting(odb));
	git_odb_close(odb);
END_TEST

78
BEGIN_TEST(odb1, "assure that alternate backends are properly sorted")
79 80 81 82 83 84 85 86 87 88 89 90 91 92
	git_odb *odb;
	must_pass(git_odb_new(&odb));
	must_pass(git_odb_add_backend(odb, new_backend(0), 5));
	must_pass(git_odb_add_backend(odb, new_backend(2), 3));
	must_pass(git_odb_add_backend(odb, new_backend(1), 4));
	must_pass(git_odb_add_backend(odb, new_backend(3), 1));
	must_pass(git_odb_add_alternate(odb, new_backend(4), 5));
	must_pass(git_odb_add_alternate(odb, new_backend(6), 3));
	must_pass(git_odb_add_alternate(odb, new_backend(5), 4));
	must_pass(git_odb_add_alternate(odb, new_backend(7), 1));
	must_pass(test_backend_sorting(odb));
	git_odb_close(odb);
END_TEST

93 94 95 96

#define STANDARD_REPOSITORY 0
#define BARE_REPOSITORY 1

97 98 99 100 101 102
static int ensure_repository_init(
	const char *working_directory,
	int repository_kind,
	const char *expected_path_index,
	const char *expected_path_repository,
	const char *expected_working_directory)
103 104 105 106
{
	char path_odb[GIT_PATH_MAX];
	git_repository *repo;

107 108
	if (gitfo_isdir(working_directory) == GIT_SUCCESS)
		return GIT_ERROR;
109 110 111

	git__joinpath(path_odb, expected_path_repository, GIT_OBJECTS_DIR);

112 113 114 115
	if (git_repository_init(&repo, working_directory, repository_kind) < GIT_SUCCESS)
		return GIT_ERROR;

	if (repo->path_workdir != NULL || expected_working_directory != NULL) {
116
		if (git__suffixcmp(repo->path_workdir, expected_working_directory) != 0)
117
			goto cleanup;
118 119
	}

120
	if (git__suffixcmp(repo->path_odb, path_odb) != 0)
121
		goto cleanup;
122

123
	if (git__suffixcmp(repo->path_repository, expected_path_repository) != 0)
124
		goto cleanup;
125 126

	if (repo->path_index != NULL || expected_path_index != NULL) {
127
		if (git__suffixcmp(repo->path_index, expected_path_index) != 0)
128
			goto cleanup;
129 130 131 132 133 134 135 136

		if (git_repository_is_bare(repo) == 1)
			goto cleanup;
	} else if (git_repository_is_bare(repo) == 0)
			goto cleanup;

	if (git_repository_is_empty(repo) == 0)
		goto cleanup;
137 138

	git_repository_free(repo);
139 140 141
	rmdir_recurs(working_directory);

	return GIT_SUCCESS;
142 143 144 145 146

cleanup:
	git_repository_free(repo);
	rmdir_recurs(working_directory);
	return GIT_ERROR;
147 148
}

149
BEGIN_TEST(init0, "initialize a standard repo")
150 151
	char path_index[GIT_PATH_MAX], path_repository[GIT_PATH_MAX];

152
	git__joinpath(path_repository, TEMP_REPO_FOLDER, GIT_DIR);
153 154
	git__joinpath(path_index, path_repository, GIT_INDEX_FILE);

155 156
	must_pass(ensure_repository_init(TEMP_REPO_FOLDER, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER));
	must_pass(ensure_repository_init(TEMP_REPO_FOLDER_NS, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER));
157 158
END_TEST

159
BEGIN_TEST(init1, "initialize a bare repo")
160 161
	char path_repository[GIT_PATH_MAX];

162
	git__joinpath(path_repository, TEMP_REPO_FOLDER, "");
163

164 165
	must_pass(ensure_repository_init(TEMP_REPO_FOLDER, BARE_REPOSITORY, NULL, path_repository, NULL));
	must_pass(ensure_repository_init(TEMP_REPO_FOLDER_NS, BARE_REPOSITORY, NULL, path_repository, NULL));
166 167
END_TEST

168
BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory")
169 170 171 172 173 174 175
	char path_repository[GIT_PATH_MAX];
	char current_workdir[GIT_PATH_MAX];
	const int mode = 0755; /* or 0777 ? */
	git_repository* repo;

	must_pass(gitfo_getcwd(current_workdir, sizeof(current_workdir)));

176
	git__joinpath(path_repository, TEMP_REPO_FOLDER, "a/b/c/");
177 178 179 180 181
	must_pass(gitfo_mkdir_recurs(path_repository, mode));

	must_pass(chdir(path_repository));

	must_pass(git_repository_init(&repo, "../d/e.git", 1));
182 183
	must_pass(git__suffixcmp(repo->path_repository, "/a/b/d/e.git/"));

184 185
	git_repository_free(repo);

186 187 188 189 190 191 192 193
	must_pass(git_repository_open(&repo, "../d/e.git"));

	git_repository_free(repo);

	must_pass(chdir(current_workdir));
	rmdir_recurs(TEMP_REPO_FOLDER);
END_TEST

194 195 196 197 198 199 200 201 202 203
#define EMPTY_BARE_REPOSITORY_NAME		"empty_bare.git"
#define EMPTY_BARE_REPOSITORY_FOLDER	TEST_RESOURCES "/" EMPTY_BARE_REPOSITORY_NAME "/"

BEGIN_TEST(open0, "Open a bare repository that has just been initialized by git")
	git_repository *repo;

	must_pass(copydir_recurs(EMPTY_BARE_REPOSITORY_FOLDER, TEMP_REPO_FOLDER));
	must_pass(remove_placeholders(TEMP_REPO_FOLDER, "dummy-marker.txt"));

	must_pass(git_repository_open(&repo, TEMP_REPO_FOLDER));
204 205
	must_be_true(git_repository_path(repo, GIT_REPO_PATH) != NULL);
	must_be_true(git_repository_path(repo, GIT_REPO_PATH_WORKDIR) == NULL);
206 207 208 209 210

	git_repository_free(repo);
	must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
END_TEST

211 212 213 214 215 216 217 218 219 220 221 222
#define SOURCE_EMPTY_REPOSITORY_NAME	"empty_standard_repo/.gitted"
#define EMPTY_REPOSITORY_NAME			"empty_standard_repo/.git"
#define EMPTY_REPOSITORY_FOLDER			TEST_RESOURCES "/" SOURCE_EMPTY_REPOSITORY_NAME "/"
#define DEST_REPOSITORY_FOLDER			TEMP_REPO_FOLDER DOT_GIT "/"

BEGIN_TEST(open1, "Open a standard repository that has just been initialized by git")
	git_repository *repo;

	must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, DEST_REPOSITORY_FOLDER));
	must_pass(remove_placeholders(DEST_REPOSITORY_FOLDER, "dummy-marker.txt"));

	must_pass(git_repository_open(&repo, DEST_REPOSITORY_FOLDER));
223 224
	must_be_true(git_repository_path(repo, GIT_REPO_PATH) != NULL);
	must_be_true(git_repository_path(repo, GIT_REPO_PATH_WORKDIR) != NULL);
225 226 227 228 229 230

	git_repository_free(repo);
	must_pass(rmdir_recurs(TEMP_REPO_FOLDER));
END_TEST


231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of the current working directory")
	char new_current_workdir[GIT_PATH_MAX];
	char current_workdir[GIT_PATH_MAX];
	char path_repository[GIT_PATH_MAX];

	const int mode = 0755; /* or 0777 ? */
	git_repository* repo;

	/* Setup the repository to open */
	must_pass(gitfo_getcwd(current_workdir, sizeof(current_workdir)));
	strcpy(path_repository, current_workdir);
	git__joinpath_n(path_repository, 3, path_repository, TEMP_REPO_FOLDER, "a/d/e.git");
	must_pass(copydir_recurs(REPOSITORY_FOLDER, path_repository));

	/* Change the current working directory */
	git__joinpath(new_current_workdir, TEMP_REPO_FOLDER, "a/b/c/");
	must_pass(gitfo_mkdir_recurs(new_current_workdir, mode));
	must_pass(chdir(new_current_workdir));

	must_pass(git_repository_open(&repo, "../../d/e.git"));

	git_repository_free(repo);

254
	must_pass(chdir(current_workdir));
255
	rmdir_recurs(TEMP_REPO_FOLDER);
256
END_TEST
257

258 259 260 261 262 263 264 265 266 267 268 269 270
BEGIN_TEST(empty0, "test if a repository is empty or not")

	git_repository *repo_empty, *repo_normal;

	must_pass(git_repository_open(&repo_normal, REPOSITORY_FOLDER));
	must_be_true(git_repository_is_empty(repo_normal) == 0);
	git_repository_free(repo_normal);

	must_pass(git_repository_open(&repo_empty, EMPTY_BARE_REPOSITORY_FOLDER));
	must_be_true(git_repository_is_empty(repo_empty) == 1);
	git_repository_free(repo_empty);
END_TEST

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
#define DISCOVER_FOLDER TEST_RESOURCES "/discover.git"

#define SUB_REPOSITORY_FOLDER_NAME "sub_repo"
#define SUB_REPOSITORY_FOLDER DISCOVER_FOLDER "/" SUB_REPOSITORY_FOLDER_NAME
#define SUB_REPOSITORY_FOLDER_SUB SUB_REPOSITORY_FOLDER "/sub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB SUB_REPOSITORY_FOLDER_SUB "/subsub"
#define SUB_REPOSITORY_FOLDER_SUB_SUB_SUB SUB_REPOSITORY_FOLDER_SUB_SUB "/subsubsub"

#define REPOSITORY_ALTERNATE_FOLDER DISCOVER_FOLDER "/alternate_sub_repo"
#define REPOSITORY_ALTERNATE_FOLDER_SUB REPOSITORY_ALTERNATE_FOLDER "/sub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB "/subsub"
#define REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/subsubsub"

#define ALTERNATE_MALFORMED_FOLDER1 DISCOVER_FOLDER "/alternate_malformed_repo1"
#define ALTERNATE_MALFORMED_FOLDER2 DISCOVER_FOLDER "/alternate_malformed_repo2"
#define ALTERNATE_MALFORMED_FOLDER3 DISCOVER_FOLDER "/alternate_malformed_repo3"
#define ALTERNATE_NOT_FOUND_FOLDER DISCOVER_FOLDER "/alternate_not_found_repo"

static int ensure_repository_discover(const char *start_path, const char *ceiling_dirs, const char *expected_path)
{
	int error;
	char found_path[GIT_PATH_MAX];

	error = git_repository_discover(found_path, sizeof(found_path), start_path, 0, ceiling_dirs);
	//across_fs is always 0 as we can't automate the filesystem change tests

	if (error < GIT_SUCCESS)
		return error;

	return strcmp(found_path, expected_path) ? GIT_ERROR : GIT_SUCCESS;
}

static int write_file(const char *path, const char *content)
{
	int error;
	git_file file;

	if (gitfo_exists(path) == GIT_SUCCESS) {
		error = gitfo_unlink(path);

		if (error < GIT_SUCCESS)
			return error;
	}

	file = gitfo_creat_force(path, 0644);
	if (file < GIT_SUCCESS)
		return file;

	error = gitfo_write(file, (void*)content, strlen(content) * sizeof(char));

	gitfo_close(file);

	return error;
}

//no check is performed on ceiling_dirs length, so be sure it's long enough
static int append_ceiling_dir(char *ceiling_dirs, const char *path)
{
	int len = strlen(ceiling_dirs);
	int error;

	error = gitfo_prettify_dir_path(ceiling_dirs + len + (len ? 1 : 0), GIT_PATH_MAX, path, NULL);
	if (error < GIT_SUCCESS)
		return git__rethrow(error, "Failed to append ceiling directory.");

	if (len)
337
		ceiling_dirs[len] = GIT_PATH_LIST_SEPARATOR;
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353

	return GIT_SUCCESS;
}

BEGIN_TEST(discover0, "test discover")
	git_repository *repo;
	char ceiling_dirs[GIT_PATH_MAX * 2] = "";
	char repository_path[GIT_PATH_MAX];
	char sub_repository_path[GIT_PATH_MAX];
	char found_path[GIT_PATH_MAX];
	int mode = 0755;

	rmdir_recurs(DISCOVER_FOLDER);
	must_pass(append_ceiling_dir(ceiling_dirs,TEST_RESOURCES));
	gitfo_mkdir_recurs(DISCOVER_FOLDER, mode);

354
	must_be_true(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs) == GIT_ENOTAREPO);
355 356 357

	must_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1));
	must_pass(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs));
358
	git_repository_free(repo);
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

	must_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0));
	must_pass(gitfo_mkdir_recurs(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
	must_pass(git_repository_discover(sub_repository_path, sizeof(sub_repository_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));

	must_pass(gitfo_mkdir_recurs(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode));
	must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, sub_repository_path));

	must_pass(gitfo_mkdir_recurs(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode));
	must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT));
	must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT));
	must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../"));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path));

	must_pass(gitfo_mkdir_recurs(ALTERNATE_MALFORMED_FOLDER1, mode));
	must_pass(write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:"));
	must_pass(gitfo_mkdir_recurs(ALTERNATE_MALFORMED_FOLDER2, mode));
	must_pass(write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:"));
	must_pass(gitfo_mkdir_recurs(ALTERNATE_MALFORMED_FOLDER3, mode));
	must_pass(write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n"));
	must_pass(gitfo_mkdir_recurs(ALTERNATE_NOT_FOUND_FOLDER, mode));
	must_pass(write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist"));
	must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs));
	must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs));
	must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs));
389
	must_be_true(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs) == GIT_ENOTAREPO);
390 391 392 393 394

	must_pass(append_ceiling_dir(ceiling_dirs, SUB_REPOSITORY_FOLDER));
	//this must pass as ceiling_directories cannot predent the current
	//working directory to be checked
	must_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
395 396 397
	must_be_true(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs) == GIT_ENOTAREPO);
	must_be_true(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs) == GIT_ENOTAREPO);
	must_be_true(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs) == GIT_ENOTAREPO);
398 399 400 401 402 403 404 405

	//.gitfile redirection should not be affected by ceiling directories
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path));
	must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path));

	rmdir_recurs(DISCOVER_FOLDER);
406
	git_repository_free(repo);
407 408
END_TEST

409 410 411 412 413
BEGIN_SUITE(repository)
	ADD_TEST(odb0);
	ADD_TEST(odb1);
	ADD_TEST(init0);
	ADD_TEST(init1);
414
	ADD_TEST(init2);
415
	ADD_TEST(open0);
416
	ADD_TEST(open1);
417
	ADD_TEST(open2);
418
	ADD_TEST(empty0);
419
	ADD_TEST(discover0);
420
END_SUITE
421