1 #include "clar_libgit2.h"
4 #include "submodule_helpers.h"
7 static git_repository
*g_repo
= NULL
;
9 void test_submodule_update__cleanup(void)
11 cl_git_sandbox_cleanup();
14 void test_submodule_update__uninitialized_submodule_no_init(void)
17 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
19 g_repo
= setup_fixture_submodule_simple();
21 /* get the submodule */
22 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
24 /* updating an uninitialized repository throws */
27 git_submodule_update(sm
, 0, &update_options
));
29 git_submodule_free(sm
);
32 struct update_submodule_cb_payload
{
33 int update_tips_called
;
34 int checkout_progress_called
;
35 int checkout_notify_called
;
38 static void checkout_progress_cb(
40 size_t completed_steps
,
44 struct update_submodule_cb_payload
*update_payload
= payload
;
47 GIT_UNUSED(completed_steps
);
48 GIT_UNUSED(total_steps
);
50 update_payload
->checkout_progress_called
= 1;
53 static int checkout_notify_cb(
54 git_checkout_notify_t why
,
56 const git_diff_file
*baseline
,
57 const git_diff_file
*target
,
58 const git_diff_file
*workdir
,
61 struct update_submodule_cb_payload
*update_payload
= payload
;
69 update_payload
->checkout_notify_called
= 1;
74 static int update_tips(const char *refname
, const git_oid
*a
, const git_oid
*b
, void *data
)
76 struct update_submodule_cb_payload
*update_payload
= data
;
82 update_payload
->update_tips_called
= 1;
87 void test_submodule_update__update_submodule(void)
90 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
91 unsigned int submodule_status
= 0;
92 struct update_submodule_cb_payload update_payload
= { 0 };
94 g_repo
= setup_fixture_submodule_simple();
96 update_options
.checkout_opts
.progress_cb
= checkout_progress_cb
;
97 update_options
.checkout_opts
.progress_payload
= &update_payload
;
99 update_options
.fetch_opts
.callbacks
.update_tips
= update_tips
;
100 update_options
.fetch_opts
.callbacks
.payload
= &update_payload
;
102 /* get the submodule */
103 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
105 /* verify the initial state of the submodule */
106 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
107 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
108 GIT_SUBMODULE_STATUS_IN_INDEX
|
109 GIT_SUBMODULE_STATUS_IN_CONFIG
|
110 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
112 /* initialize and update the submodule */
113 cl_git_pass(git_submodule_init(sm
, 0));
114 cl_git_pass(git_submodule_update(sm
, 0, &update_options
));
117 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
118 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
119 GIT_SUBMODULE_STATUS_IN_INDEX
|
120 GIT_SUBMODULE_STATUS_IN_CONFIG
|
121 GIT_SUBMODULE_STATUS_IN_WD
);
123 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
124 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
125 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
127 /* verify that the expected callbacks have been called. */
128 cl_assert_equal_i(1, update_payload
.checkout_progress_called
);
129 cl_assert_equal_i(1, update_payload
.update_tips_called
);
131 git_submodule_free(sm
);
134 void test_submodule_update__update_submodule_with_path(void)
137 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
138 unsigned int submodule_status
= 0;
139 struct update_submodule_cb_payload update_payload
= { 0 };
141 g_repo
= setup_fixture_submodule_with_path();
143 update_options
.checkout_opts
.progress_cb
= checkout_progress_cb
;
144 update_options
.checkout_opts
.progress_payload
= &update_payload
;
146 update_options
.fetch_opts
.callbacks
.update_tips
= update_tips
;
147 update_options
.fetch_opts
.callbacks
.payload
= &update_payload
;
149 /* get the submodule */
150 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
152 /* verify the initial state of the submodule */
153 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
154 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
155 GIT_SUBMODULE_STATUS_IN_INDEX
|
156 GIT_SUBMODULE_STATUS_IN_CONFIG
|
157 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
159 /* initialize and update the submodule */
160 cl_git_pass(git_submodule_init(sm
, 0));
161 cl_git_pass(git_submodule_update(sm
, 0, &update_options
));
164 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
165 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
166 GIT_SUBMODULE_STATUS_IN_INDEX
|
167 GIT_SUBMODULE_STATUS_IN_CONFIG
|
168 GIT_SUBMODULE_STATUS_IN_WD
);
170 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
171 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
172 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
174 /* verify that the expected callbacks have been called. */
175 cl_assert_equal_i(1, update_payload
.checkout_progress_called
);
176 cl_assert_equal_i(1, update_payload
.update_tips_called
);
178 git_submodule_free(sm
);
181 void test_submodule_update__update_and_init_submodule(void)
184 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
185 unsigned int submodule_status
= 0;
187 g_repo
= setup_fixture_submodule_simple();
189 /* get the submodule */
190 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
192 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
193 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
194 GIT_SUBMODULE_STATUS_IN_INDEX
|
195 GIT_SUBMODULE_STATUS_IN_CONFIG
|
196 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
198 /* update (with option to initialize sub repo) */
199 cl_git_pass(git_submodule_update(sm
, 1, &update_options
));
201 /* verify expected state */
202 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
203 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
204 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
206 git_submodule_free(sm
);
209 void test_submodule_update__update_already_checked_out_submodule(void)
211 git_submodule
*sm
= NULL
;
212 git_checkout_options checkout_options
= GIT_CHECKOUT_OPTIONS_INIT
;
213 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
214 unsigned int submodule_status
= 0;
215 git_reference
*branch_reference
= NULL
;
216 git_object
*branch_commit
= NULL
;
217 struct update_submodule_cb_payload update_payload
= { 0 };
219 g_repo
= setup_fixture_submodule_simple();
221 update_options
.checkout_opts
.progress_cb
= checkout_progress_cb
;
222 update_options
.checkout_opts
.progress_payload
= &update_payload
;
224 /* Initialize and update the sub repository */
225 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
227 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
228 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
229 GIT_SUBMODULE_STATUS_IN_INDEX
|
230 GIT_SUBMODULE_STATUS_IN_CONFIG
|
231 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
233 cl_git_pass(git_submodule_update(sm
, 1, &update_options
));
235 /* verify expected state */
236 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
237 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
238 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
240 /* checkout the alternate_1 branch */
241 checkout_options
.checkout_strategy
= GIT_CHECKOUT_SAFE
;
243 cl_git_pass(git_reference_lookup(&branch_reference
, g_repo
, "refs/heads/alternate_1"));
244 cl_git_pass(git_reference_peel(&branch_commit
, branch_reference
, GIT_OBJECT_COMMIT
));
245 cl_git_pass(git_checkout_tree(g_repo
, branch_commit
, &checkout_options
));
246 cl_git_pass(git_repository_set_head(g_repo
, git_reference_name(branch_reference
)));
249 * Verify state after checkout of parent repository. The submodule ID in the
250 * HEAD commit and index should be updated, but not the workdir.
253 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
255 git_submodule_free(sm
);
256 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
258 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
259 GIT_SUBMODULE_STATUS_IN_INDEX
|
260 GIT_SUBMODULE_STATUS_IN_CONFIG
|
261 GIT_SUBMODULE_STATUS_IN_WD
|
262 GIT_SUBMODULE_STATUS_WD_MODIFIED
);
264 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
265 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
266 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
269 * Update the submodule and verify the state.
270 * Now, the HEAD, index, and Workdir commits should all be updated to
273 cl_git_pass(git_submodule_update(sm
, 0, &update_options
));
274 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
275 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
276 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
278 /* verify that the expected callbacks have been called. */
279 cl_assert_equal_i(1, update_payload
.checkout_progress_called
);
281 git_submodule_free(sm
);
282 git_object_free(branch_commit
);
283 git_reference_free(branch_reference
);
286 void test_submodule_update__update_blocks_on_dirty_wd(void)
288 git_submodule
*sm
= NULL
;
289 git_checkout_options checkout_options
= GIT_CHECKOUT_OPTIONS_INIT
;
290 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
291 unsigned int submodule_status
= 0;
292 git_reference
*branch_reference
= NULL
;
293 git_object
*branch_commit
= NULL
;
294 struct update_submodule_cb_payload update_payload
= { 0 };
296 g_repo
= setup_fixture_submodule_simple();
298 update_options
.checkout_opts
.notify_flags
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
299 update_options
.checkout_opts
.notify_cb
= checkout_notify_cb
;
300 update_options
.checkout_opts
.notify_payload
= &update_payload
;
302 /* Initialize and update the sub repository */
303 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
305 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
306 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
307 GIT_SUBMODULE_STATUS_IN_INDEX
|
308 GIT_SUBMODULE_STATUS_IN_CONFIG
|
309 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
311 cl_git_pass(git_submodule_update(sm
, 1, &update_options
));
313 /* verify expected state */
314 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
315 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
316 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
318 /* checkout the alternate_1 branch */
319 checkout_options
.checkout_strategy
= GIT_CHECKOUT_SAFE
;
321 cl_git_pass(git_reference_lookup(&branch_reference
, g_repo
, "refs/heads/alternate_1"));
322 cl_git_pass(git_reference_peel(&branch_commit
, branch_reference
, GIT_OBJECT_COMMIT
));
323 cl_git_pass(git_checkout_tree(g_repo
, branch_commit
, &checkout_options
));
324 cl_git_pass(git_repository_set_head(g_repo
, git_reference_name(branch_reference
)));
327 * Verify state after checkout of parent repository. The submodule ID in the
328 * HEAD commit and index should be updated, but not the workdir.
331 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
333 git_submodule_free(sm
);
334 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
336 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
337 GIT_SUBMODULE_STATUS_IN_INDEX
|
338 GIT_SUBMODULE_STATUS_IN_CONFIG
|
339 GIT_SUBMODULE_STATUS_IN_WD
|
340 GIT_SUBMODULE_STATUS_WD_MODIFIED
);
342 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
343 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
344 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
347 * Create a conflicting edit in the subrepository to verify that
348 * the submodule update action is blocked.
350 cl_git_write2file("submodule_simple/testrepo/branch_file.txt", "a conflicting edit", 0,
351 O_WRONLY
| O_CREAT
| O_TRUNC
, 0755);
353 cl_git_fail(git_submodule_update(sm
, 0, &update_options
));
355 /* verify that the expected callbacks have been called. */
356 cl_assert_equal_i(1, update_payload
.checkout_notify_called
);
358 /* verify that the submodule state has not changed. */
359 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
360 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
361 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
363 git_submodule_free(sm
);
364 git_object_free(branch_commit
);
365 git_reference_free(branch_reference
);
368 void test_submodule_update__can_force_update(void)
370 git_submodule
*sm
= NULL
;
371 git_checkout_options checkout_options
= GIT_CHECKOUT_OPTIONS_INIT
;
372 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
373 unsigned int submodule_status
= 0;
374 git_reference
*branch_reference
= NULL
;
375 git_object
*branch_commit
= NULL
;
377 g_repo
= setup_fixture_submodule_simple();
379 /* Initialize and update the sub repository */
380 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
382 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
383 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
384 GIT_SUBMODULE_STATUS_IN_INDEX
|
385 GIT_SUBMODULE_STATUS_IN_CONFIG
|
386 GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
);
388 cl_git_pass(git_submodule_update(sm
, 1, &update_options
));
390 /* verify expected state */
391 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
392 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
393 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
395 /* checkout the alternate_1 branch */
396 checkout_options
.checkout_strategy
= GIT_CHECKOUT_SAFE
;
398 cl_git_pass(git_reference_lookup(&branch_reference
, g_repo
, "refs/heads/alternate_1"));
399 cl_git_pass(git_reference_peel(&branch_commit
, branch_reference
, GIT_OBJECT_COMMIT
));
400 cl_git_pass(git_checkout_tree(g_repo
, branch_commit
, &checkout_options
));
401 cl_git_pass(git_repository_set_head(g_repo
, git_reference_name(branch_reference
)));
404 * Verify state after checkout of parent repository. The submodule ID in the
405 * HEAD commit and index should be updated, but not the workdir.
407 cl_git_pass(git_submodule_status(&submodule_status
, g_repo
, "testrepo", GIT_SUBMODULE_IGNORE_UNSPECIFIED
));
409 git_submodule_free(sm
);
410 cl_git_pass(git_submodule_lookup(&sm
, g_repo
, "testrepo"));
412 cl_assert_equal_i(submodule_status
, GIT_SUBMODULE_STATUS_IN_HEAD
|
413 GIT_SUBMODULE_STATUS_IN_INDEX
|
414 GIT_SUBMODULE_STATUS_IN_CONFIG
|
415 GIT_SUBMODULE_STATUS_IN_WD
|
416 GIT_SUBMODULE_STATUS_WD_MODIFIED
);
418 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
419 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644") == 0);
420 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
423 * Create a conflicting edit in the subrepository to verify that
424 * the submodule update action is blocked.
426 cl_git_write2file("submodule_simple/testrepo/branch_file.txt", "a conflicting edit", 0,
427 O_WRONLY
| O_CREAT
| O_TRUNC
, 0777);
429 /* forcefully checkout and verify the submodule state was updated. */
430 update_options
.checkout_opts
.checkout_strategy
= GIT_CHECKOUT_FORCE
;
431 cl_git_pass(git_submodule_update(sm
, 0, &update_options
));
432 cl_assert(git_oid_streq(git_submodule_head_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
433 cl_assert(git_oid_streq(git_submodule_wd_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
434 cl_assert(git_oid_streq(git_submodule_index_id(sm
), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750") == 0);
436 git_submodule_free(sm
);
437 git_object_free(branch_commit
);
438 git_reference_free(branch_reference
);