Commit c3414d53 by Carlos Martín Nieto

Merge pull request #3070 from ethomson/checkout_icase

Case insensitive checkout improvements
parents cfc2e56d cd79d99a
...@@ -124,6 +124,11 @@ typedef enum { ...@@ -124,6 +124,11 @@ typedef enum {
/** Use case insensitive filename comparisons */ /** Use case insensitive filename comparisons */
GIT_DIFF_IGNORE_CASE = (1u << 10), GIT_DIFF_IGNORE_CASE = (1u << 10),
/** May be combined with `GIT_DIFF_IGNORE_CASE` to specify that a file
* that has changed case will be returned as an add/delete pair.
*/
GIT_DIFF_INCLUDE_CASECHANGE = (1u << 11),
/** If the pathspec is set in the diff options, this flags means to /** If the pathspec is set in the diff options, this flags means to
* apply it as an exact match instead of as an fnmatch pattern. * apply it as an exact match instead of as an fnmatch pattern.
*/ */
...@@ -220,7 +225,7 @@ typedef struct git_diff git_diff; ...@@ -220,7 +225,7 @@ typedef struct git_diff git_diff;
typedef enum { typedef enum {
GIT_DIFF_FLAG_BINARY = (1u << 0), /**< file(s) treated as binary data */ GIT_DIFF_FLAG_BINARY = (1u << 0), /**< file(s) treated as binary data */
GIT_DIFF_FLAG_NOT_BINARY = (1u << 1), /**< file(s) treated as text data */ GIT_DIFF_FLAG_NOT_BINARY = (1u << 1), /**< file(s) treated as text data */
GIT_DIFF_FLAG_VALID_ID = (1u << 2), /**< `id` value is known correct */ GIT_DIFF_FLAG_VALID_ID = (1u << 2), /**< `id` value is known correct */
} git_diff_flag_t; } git_diff_flag_t;
/** /**
......
...@@ -409,6 +409,14 @@ static bool submodule_is_config_only( ...@@ -409,6 +409,14 @@ static bool submodule_is_config_only(
return rval; return rval;
} }
static bool checkout_is_empty_dir(checkout_data *data, const char *path)
{
git_buf_truncate(&data->path, data->workdir_len);
if (git_buf_puts(&data->path, path) < 0)
return false;
return git_path_is_empty_dir(data->path.ptr);
}
static int checkout_action_with_wd( static int checkout_action_with_wd(
int *action, int *action,
checkout_data *data, checkout_data *data,
...@@ -526,6 +534,7 @@ static int checkout_action_with_wd_dir( ...@@ -526,6 +534,7 @@ static int checkout_action_with_wd_dir(
checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)); checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL));
GITERR_CHECK_ERROR( GITERR_CHECK_ERROR(
checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)); checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
*action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
break; break;
case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */ case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */ case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
...@@ -550,8 +559,6 @@ static int checkout_action_with_wd_dir( ...@@ -550,8 +559,6 @@ static int checkout_action_with_wd_dir(
* dir and it will succeed if no children are left. * dir and it will succeed if no children are left.
*/ */
*action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
if (*action != CHECKOUT_ACTION__NONE)
*action |= CHECKOUT_ACTION__DEFER_REMOVE;
} }
else if (delta->new_file.mode != GIT_FILEMODE_TREE) else if (delta->new_file.mode != GIT_FILEMODE_TREE)
/* For typechange to dir, dir is already created so no action */ /* For typechange to dir, dir is already created so no action */
...@@ -564,6 +571,20 @@ static int checkout_action_with_wd_dir( ...@@ -564,6 +571,20 @@ static int checkout_action_with_wd_dir(
return checkout_action_common(action, data, delta, wd); return checkout_action_common(action, data, delta, wd);
} }
static int checkout_action_with_wd_dir_empty(
int *action,
checkout_data *data,
const git_diff_delta *delta)
{
int error = checkout_action_no_wd(action, data, delta);
/* We can always safely remove an empty directory. */
if (error == 0 && *action != CHECKOUT_ACTION__NONE)
*action |= CHECKOUT_ACTION__REMOVE;
return error;
}
static int checkout_action( static int checkout_action(
int *action, int *action,
checkout_data *data, checkout_data *data,
...@@ -653,7 +674,9 @@ static int checkout_action( ...@@ -653,7 +674,9 @@ static int checkout_action(
} }
} }
return checkout_action_with_wd_dir(action, data, delta, workdir, wd); return checkout_is_empty_dir(data, wd->path) ?
checkout_action_with_wd_dir_empty(action, data, delta) :
checkout_action_with_wd_dir(action, data, delta, workdir, wd);
} }
/* case 6 - wd is after delta */ /* case 6 - wd is after delta */
...@@ -2462,7 +2485,8 @@ int git_checkout_iterator( ...@@ -2462,7 +2485,8 @@ int git_checkout_iterator(
GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_IGNORED |
GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_INCLUDE_TYPECHANGE |
GIT_DIFF_INCLUDE_TYPECHANGE_TREES | GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
GIT_DIFF_SKIP_BINARY_CHECK; GIT_DIFF_SKIP_BINARY_CHECK |
GIT_DIFF_INCLUDE_CASECHANGE;
if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH; diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
if (data.opts.paths.count > 0) if (data.opts.paths.count > 0)
...@@ -2643,7 +2667,7 @@ int git_checkout_tree( ...@@ -2643,7 +2667,7 @@ int git_checkout_tree(
if ((error = git_repository_index(&index, repo)) < 0) if ((error = git_repository_index(&index, repo)) < 0)
return error; return error;
if (!(error = git_iterator_for_tree(&tree_i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL))) if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
error = git_checkout_iterator(tree_i, index, opts); error = git_checkout_iterator(tree_i, index, opts);
git_iterator_free(tree_i); git_iterator_free(tree_i);
......
...@@ -822,6 +822,19 @@ static int maybe_modified( ...@@ -822,6 +822,19 @@ static int maybe_modified(
status = GIT_DELTA_UNMODIFIED; status = GIT_DELTA_UNMODIFIED;
} }
/* If we want case changes, then break this into a delete of the old
* and an add of the new so that consumers can act accordingly (eg,
* checkout will update the case on disk.)
*/
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE) &&
DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_CASECHANGE) &&
strcmp(oitem->path, nitem->path) != 0) {
if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem)))
error = diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem);
return error;
}
return diff_delta__from_two( return diff_delta__from_two(
diff, status, oitem, omode, nitem, nmode, diff, status, oitem, omode, nitem, nmode,
git_oid_iszero(&noid) ? NULL : &noid, matched_pathspec); git_oid_iszero(&noid) ? NULL : &noid, matched_pathspec);
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "git2/checkout.h" #include "git2/checkout.h"
#include "refs.h"
#include "path.h" #include "path.h"
#ifdef GIT_WIN32 #ifdef GIT_WIN32
# include <windows.h> # include <windows.h>
#else
# include <dirent.h>
#endif #endif
static git_repository *repo; static git_repository *repo;
...@@ -14,14 +17,23 @@ static git_checkout_options checkout_opts; ...@@ -14,14 +17,23 @@ static git_checkout_options checkout_opts;
void test_checkout_icase__initialize(void) void test_checkout_icase__initialize(void)
{ {
git_oid id; git_oid id;
git_config *cfg;
int icase = 0;
repo = cl_git_sandbox_init("testrepo"); repo = cl_git_sandbox_init("testrepo");
cl_git_pass(git_repository_config_snapshot(&cfg, repo));
git_config_get_bool(&icase, cfg, "core.ignorecase");
git_config_free(cfg);
if (!icase)
cl_skip();
cl_git_pass(git_reference_name_to_id(&id, repo, "refs/heads/dir")); cl_git_pass(git_reference_name_to_id(&id, repo, "refs/heads/dir"));
cl_git_pass(git_object_lookup(&obj, repo, &id, GIT_OBJ_ANY)); cl_git_pass(git_object_lookup(&obj, repo, &id, GIT_OBJ_ANY));
git_checkout_init_options(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION); git_checkout_init_options(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
} }
void test_checkout_icase__cleanup(void) void test_checkout_icase__cleanup(void)
...@@ -30,7 +42,7 @@ void test_checkout_icase__cleanup(void) ...@@ -30,7 +42,7 @@ void test_checkout_icase__cleanup(void)
cl_git_sandbox_cleanup(); cl_git_sandbox_cleanup();
} }
static char *test_realpath(const char *in) static char *get_filename(const char *in)
{ {
#ifdef GIT_WIN32 #ifdef GIT_WIN32
HANDLE fh; HANDLE fh;
...@@ -55,7 +67,31 @@ static char *test_realpath(const char *in) ...@@ -55,7 +67,31 @@ static char *test_realpath(const char *in)
return filename; return filename;
#else #else
return realpath(in, NULL); char *search_dirname, *search_filename, *filename = NULL;
git_buf out = GIT_BUF_INIT;
DIR *dir;
struct dirent *de;
cl_assert(search_dirname = git_path_dirname(in));
cl_assert(search_filename = git_path_basename(in));
cl_assert(dir = opendir(search_dirname));
while ((de = readdir(dir))) {
if (strcasecmp(de->d_name, search_filename) == 0) {
git_buf_join(&out, '/', search_dirname, de->d_name);
filename = git_buf_detach(&out);
break;
}
}
closedir(dir);
git__free(search_dirname);
git__free(search_filename);
git_buf_free(&out);
return filename;
#endif #endif
} }
...@@ -64,7 +100,7 @@ static void assert_name_is(const char *expected) ...@@ -64,7 +100,7 @@ static void assert_name_is(const char *expected)
char *actual; char *actual;
size_t actual_len, expected_len, start; size_t actual_len, expected_len, start;
cl_assert(actual = test_realpath(expected)); cl_assert(actual = get_filename(expected));
expected_len = strlen(expected); expected_len = strlen(expected);
actual_len = strlen(actual); actual_len = strlen(actual);
...@@ -79,8 +115,21 @@ static void assert_name_is(const char *expected) ...@@ -79,8 +115,21 @@ static void assert_name_is(const char *expected)
free(actual); free(actual);
} }
void test_checkout_icase__overwrites_files_for_files(void) void test_checkout_icase__refuses_to_overwrite_files_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_git_write2file("testrepo/BRANCH_FILE.txt", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644);
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
assert_name_is("testrepo/BRANCH_FILE.txt");
}
void test_checkout_icase__overwrites_files_for_files_when_forced(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_write2file("testrepo/NEW.txt", "neue file\n", 10, \ cl_git_write2file("testrepo/NEW.txt", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644); O_WRONLY | O_CREAT | O_TRUNC, 0644);
...@@ -88,8 +137,22 @@ void test_checkout_icase__overwrites_files_for_files(void) ...@@ -88,8 +137,22 @@ void test_checkout_icase__overwrites_files_for_files(void)
assert_name_is("testrepo/new.txt"); assert_name_is("testrepo/new.txt");
} }
void test_checkout_icase__overwrites_links_for_files(void) void test_checkout_icase__refuses_to_overwrite_links_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_symlink("../tmp", "testrepo/BRANCH_FILE.txt"));
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
cl_assert(!git_path_exists("tmp"));
assert_name_is("testrepo/BRANCH_FILE.txt");
}
void test_checkout_icase__overwrites_links_for_files_when_forced(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_must_pass(p_symlink("../tmp", "testrepo/NEW.txt")); cl_must_pass(p_symlink("../tmp", "testrepo/NEW.txt"));
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -98,8 +161,10 @@ void test_checkout_icase__overwrites_links_for_files(void) ...@@ -98,8 +161,10 @@ void test_checkout_icase__overwrites_links_for_files(void)
assert_name_is("testrepo/new.txt"); assert_name_is("testrepo/new.txt");
} }
void test_checkout_icase__overwites_folders_for_files(void) void test_checkout_icase__overwrites_empty_folders_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777)); cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777));
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -108,8 +173,50 @@ void test_checkout_icase__overwites_folders_for_files(void) ...@@ -108,8 +173,50 @@ void test_checkout_icase__overwites_folders_for_files(void)
cl_assert(!git_path_isdir("testrepo/new.txt")); cl_assert(!git_path_isdir("testrepo/new.txt"));
} }
void test_checkout_icase__overwrites_files_for_folders(void) void test_checkout_icase__refuses_to_overwrite_populated_folders_for_files(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_mkdir("testrepo/BRANCH_FILE.txt", 0777));
cl_git_write2file("testrepo/BRANCH_FILE.txt/foobar", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644);
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
assert_name_is("testrepo/BRANCH_FILE.txt");
cl_assert(git_path_isdir("testrepo/BRANCH_FILE.txt"));
}
void test_checkout_icase__overwrites_folders_for_files_when_forced(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_must_pass(p_mkdir("testrepo/NEW.txt", 0777));
cl_git_write2file("testrepo/NEW.txt/foobar", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644);
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
assert_name_is("testrepo/new.txt");
cl_assert(!git_path_isdir("testrepo/new.txt"));
}
void test_checkout_icase__refuses_to_overwrite_files_for_folders(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_git_write2file("testrepo/A", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644);
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
assert_name_is("testrepo/A");
cl_assert(!git_path_isdir("testrepo/A"));
}
void test_checkout_icase__overwrites_files_for_folders_when_forced(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_write2file("testrepo/A", "neue file\n", 10, \ cl_git_write2file("testrepo/A", "neue file\n", 10, \
O_WRONLY | O_CREAT | O_TRUNC, 0644); O_WRONLY | O_CREAT | O_TRUNC, 0644);
...@@ -118,8 +225,22 @@ void test_checkout_icase__overwrites_files_for_folders(void) ...@@ -118,8 +225,22 @@ void test_checkout_icase__overwrites_files_for_folders(void)
cl_assert(git_path_isdir("testrepo/a")); cl_assert(git_path_isdir("testrepo/a"));
} }
void test_checkout_icase__overwrites_links_for_folders(void) void test_checkout_icase__refuses_to_overwrite_links_for_folders(void)
{
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE|GIT_CHECKOUT_RECREATE_MISSING;
cl_must_pass(p_symlink("..", "testrepo/A"));
cl_git_fail(git_checkout_tree(repo, obj, &checkout_opts));
cl_assert(!git_path_exists("b.txt"));
assert_name_is("testrepo/A");
}
void test_checkout_icase__overwrites_links_for_folders_when_forced(void)
{ {
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_must_pass(p_symlink("..", "testrepo/A")); cl_must_pass(p_symlink("..", "testrepo/A"));
cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts)); cl_git_pass(git_checkout_tree(repo, obj, &checkout_opts));
...@@ -128,3 +249,53 @@ void test_checkout_icase__overwrites_links_for_folders(void) ...@@ -128,3 +249,53 @@ void test_checkout_icase__overwrites_links_for_folders(void)
assert_name_is("testrepo/a"); assert_name_is("testrepo/a");
} }
void test_checkout_icase__ignores_unstaged_casechange(void)
{
git_reference *orig_ref, *br2_ref;
git_commit *orig, *br2;
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
cl_git_pass(git_reference_lookup_resolved(&orig_ref, repo, "HEAD", 100));
cl_git_pass(git_commit_lookup(&orig, repo, git_reference_target(orig_ref)));
cl_git_pass(git_reset(repo, (git_object *)orig, GIT_RESET_HARD, NULL));
cl_rename("testrepo/branch_file.txt", "testrepo/Branch_File.txt");
cl_git_pass(git_reference_lookup_resolved(&br2_ref, repo, "refs/heads/br2", 100));
cl_git_pass(git_commit_lookup(&br2, repo, git_reference_target(br2_ref)));
cl_git_pass(git_checkout_tree(repo, (const git_object *)br2, &checkout_opts));
git_commit_free(orig);
git_reference_free(orig_ref);
}
void test_checkout_icase__conflicts_with_casechanged_subtrees(void)
{
git_reference *orig_ref;
git_object *orig, *subtrees;
git_oid oid;
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
cl_git_pass(git_reference_lookup_resolved(&orig_ref, repo, "HEAD", 100));
cl_git_pass(git_object_lookup(&orig, repo, git_reference_target(orig_ref), GIT_OBJ_COMMIT));
cl_git_pass(git_reset(repo, (git_object *)orig, GIT_RESET_HARD, NULL));
cl_must_pass(p_mkdir("testrepo/AB", 0777));
cl_must_pass(p_mkdir("testrepo/AB/C", 0777));
cl_git_write2file("testrepo/AB/C/3.txt", "Foobar!\n", 8, O_RDWR|O_CREAT, 0666);
cl_git_pass(git_reference_name_to_id(&oid, repo, "refs/heads/subtrees"));
cl_git_pass(git_object_lookup(&subtrees, repo, &oid, GIT_OBJ_ANY));
cl_git_fail(git_checkout_tree(repo, subtrees, &checkout_opts));
git_object_free(orig);
git_object_free(subtrees);
git_reference_free(orig_ref);
}
...@@ -646,7 +646,14 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void) ...@@ -646,7 +646,14 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void)
cl_git_fail_with(git_checkout_tree(g_repo, obj, &opts), -5555); cl_git_fail_with(git_checkout_tree(g_repo, obj, &opts), -5555);
cl_assert(!git_path_exists("testrepo/new.txt")); cl_assert(!git_path_exists("testrepo/new.txt"));
cl_assert_equal_i(4, ca.count);
/* on case-insensitive FS = a/b.txt, branch_file.txt, new.txt */
/* on case-sensitive FS = README, then above */
if (git_path_exists("testrepo/.git/CoNfIg")) /* case insensitive */
cl_assert_equal_i(3, ca.count);
else
cl_assert_equal_i(4, ca.count);
/* and again with a different stopping point and return code */ /* and again with a different stopping point and return code */
ca.filename = "README"; ca.filename = "README";
...@@ -656,7 +663,11 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void) ...@@ -656,7 +663,11 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void)
cl_git_fail_with(git_checkout_tree(g_repo, obj, &opts), 123); cl_git_fail_with(git_checkout_tree(g_repo, obj, &opts), 123);
cl_assert(!git_path_exists("testrepo/new.txt")); cl_assert(!git_path_exists("testrepo/new.txt"));
cl_assert_equal_i(1, ca.count);
if (git_path_exists("testrepo/.git/CoNfIg")) /* case insensitive */
cl_assert_equal_i(4, ca.count);
else
cl_assert_equal_i(1, ca.count);
git_object_free(obj); git_object_free(obj);
} }
......
...@@ -73,16 +73,20 @@ static void check_status( ...@@ -73,16 +73,20 @@ static void check_status(
cl_assert_equal_i_fmt(expected->status, actual->status, "%04x"); cl_assert_equal_i_fmt(expected->status, actual->status, "%04x");
if (oldname) if (expected->oldname) {
cl_assert(git__strcmp(oldname, expected->oldname) == 0); cl_assert(oldname != NULL);
else cl_assert_equal_s(oldname, expected->oldname);
cl_assert(expected->oldname == NULL); } else {
cl_assert(oldname == NULL);
}
if (actual->status & (GIT_STATUS_INDEX_RENAMED|GIT_STATUS_WT_RENAMED)) { if (actual->status & (GIT_STATUS_INDEX_RENAMED|GIT_STATUS_WT_RENAMED)) {
if (newname) if (expected->newname) {
cl_assert(git__strcmp(newname, expected->newname) == 0); cl_assert(newname != NULL);
else cl_assert_equal_s(newname, expected->newname);
cl_assert(expected->newname == NULL); } else {
cl_assert(newname == NULL);
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment