]> git.ipfire.org Git - thirdparty/git.git/blob - t/t7814-grep-recurse-submodules.sh
The third batch
[thirdparty/git.git] / t / t7814-grep-recurse-submodules.sh
1 #!/bin/sh
2
3 test_description='Test grep recurse-submodules feature
4
5 This test verifies the recurse-submodules feature correctly greps across
6 submodules.
7 '
8
9 TEST_CREATE_REPO_NO_TEMPLATE=1
10 . ./test-lib.sh
11
12 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
13 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
14
15 test_expect_success 'setup directory structure and submodule' '
16 echo "(1|2)d(3|4)" >a &&
17 mkdir b &&
18 echo "(3|4)" >b/b &&
19 git add a b &&
20 git commit -m "add a and b" &&
21 test_tick &&
22 git init submodule &&
23 echo "(1|2)d(3|4)" >submodule/a &&
24 git -C submodule add a &&
25 git -C submodule commit -m "add a" &&
26 git submodule add ./submodule &&
27 git commit -m "added submodule" &&
28 test_tick
29 '
30
31 test_expect_success 'grep correctly finds patterns in a submodule' '
32 cat >expect <<-\EOF &&
33 a:(1|2)d(3|4)
34 b/b:(3|4)
35 submodule/a:(1|2)d(3|4)
36 EOF
37
38 git grep -e "(3|4)" --recurse-submodules >actual &&
39 test_cmp expect actual
40 '
41
42 test_expect_success 'grep finds patterns in a submodule via config' '
43 test_config submodule.recurse true &&
44 # expect from previous test
45 git grep -e "(3|4)" >actual &&
46 test_cmp expect actual
47 '
48
49 test_expect_success 'grep --no-recurse-submodules overrides config' '
50 test_config submodule.recurse true &&
51 cat >expect <<-\EOF &&
52 a:(1|2)d(3|4)
53 b/b:(3|4)
54 EOF
55
56 git grep -e "(3|4)" --no-recurse-submodules >actual &&
57 test_cmp expect actual
58 '
59
60 test_expect_success 'grep and basic pathspecs' '
61 cat >expect <<-\EOF &&
62 submodule/a:(1|2)d(3|4)
63 EOF
64
65 git grep -e. --recurse-submodules -- submodule >actual &&
66 test_cmp expect actual
67 '
68
69 test_expect_success 'grep and nested submodules' '
70 git init submodule/sub &&
71 echo "(1|2)d(3|4)" >submodule/sub/a &&
72 git -C submodule/sub add a &&
73 git -C submodule/sub commit -m "add a" &&
74 test_tick &&
75 git -C submodule submodule add ./sub &&
76 git -C submodule add sub &&
77 git -C submodule commit -m "added sub" &&
78 test_tick &&
79 git add submodule &&
80 git commit -m "updated submodule" &&
81 test_tick &&
82
83 cat >expect <<-\EOF &&
84 a:(1|2)d(3|4)
85 b/b:(3|4)
86 submodule/a:(1|2)d(3|4)
87 submodule/sub/a:(1|2)d(3|4)
88 EOF
89
90 git grep -e "(3|4)" --recurse-submodules >actual &&
91 test_cmp expect actual
92 '
93
94 test_expect_success 'grep and multiple patterns' '
95 cat >expect <<-\EOF &&
96 a:(1|2)d(3|4)
97 submodule/a:(1|2)d(3|4)
98 submodule/sub/a:(1|2)d(3|4)
99 EOF
100
101 git grep -e "(3|4)" --and -e "(1|2)" --recurse-submodules >actual &&
102 test_cmp expect actual
103 '
104
105 test_expect_success 'grep and multiple patterns' '
106 cat >expect <<-\EOF &&
107 b/b:(3|4)
108 EOF
109
110 git grep -e "(3|4)" --and --not -e "(1|2)" --recurse-submodules >actual &&
111 test_cmp expect actual
112 '
113
114 test_expect_success 'basic grep tree' '
115 cat >expect <<-\EOF &&
116 HEAD:a:(1|2)d(3|4)
117 HEAD:b/b:(3|4)
118 HEAD:submodule/a:(1|2)d(3|4)
119 HEAD:submodule/sub/a:(1|2)d(3|4)
120 EOF
121
122 git grep -e "(3|4)" --recurse-submodules HEAD >actual &&
123 test_cmp expect actual
124 '
125
126 test_expect_success 'grep tree HEAD^' '
127 cat >expect <<-\EOF &&
128 HEAD^:a:(1|2)d(3|4)
129 HEAD^:b/b:(3|4)
130 HEAD^:submodule/a:(1|2)d(3|4)
131 EOF
132
133 git grep -e "(3|4)" --recurse-submodules HEAD^ >actual &&
134 test_cmp expect actual
135 '
136
137 test_expect_success 'grep tree HEAD^^' '
138 cat >expect <<-\EOF &&
139 HEAD^^:a:(1|2)d(3|4)
140 HEAD^^:b/b:(3|4)
141 EOF
142
143 git grep -e "(3|4)" --recurse-submodules HEAD^^ >actual &&
144 test_cmp expect actual
145 '
146
147 test_expect_success 'grep tree and pathspecs' '
148 cat >expect <<-\EOF &&
149 HEAD:submodule/a:(1|2)d(3|4)
150 HEAD:submodule/sub/a:(1|2)d(3|4)
151 EOF
152
153 git grep -e "(3|4)" --recurse-submodules HEAD -- submodule >actual &&
154 test_cmp expect actual
155 '
156
157 test_expect_success 'grep tree and pathspecs' '
158 cat >expect <<-\EOF &&
159 HEAD:submodule/a:(1|2)d(3|4)
160 HEAD:submodule/sub/a:(1|2)d(3|4)
161 EOF
162
163 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodule*a" >actual &&
164 test_cmp expect actual
165 '
166
167 test_expect_success 'grep tree and more pathspecs' '
168 cat >expect <<-\EOF &&
169 HEAD:submodule/a:(1|2)d(3|4)
170 EOF
171
172 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul?/a" >actual &&
173 test_cmp expect actual
174 '
175
176 test_expect_success 'grep tree and more pathspecs' '
177 cat >expect <<-\EOF &&
178 HEAD:submodule/sub/a:(1|2)d(3|4)
179 EOF
180
181 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul*/sub/a" >actual &&
182 test_cmp expect actual
183 '
184
185 test_expect_success !MINGW 'grep recurse submodule colon in name' '
186 git init parent &&
187 test_when_finished "rm -rf parent" &&
188 echo "(1|2)d(3|4)" >"parent/fi:le" &&
189 git -C parent add "fi:le" &&
190 git -C parent commit -m "add fi:le" &&
191 test_tick &&
192
193 git init "su:b" &&
194 test_when_finished "rm -rf su:b" &&
195 echo "(1|2)d(3|4)" >"su:b/fi:le" &&
196 git -C "su:b" add "fi:le" &&
197 git -C "su:b" commit -m "add fi:le" &&
198 test_tick &&
199
200 test_config_global protocol.file.allow always &&
201 git -C parent submodule add "../su:b" "su:b" &&
202 git -C parent commit -m "add submodule" &&
203 test_tick &&
204
205 cat >expect <<-\EOF &&
206 fi:le:(1|2)d(3|4)
207 su:b/fi:le:(1|2)d(3|4)
208 EOF
209 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
210 test_cmp expect actual &&
211
212 cat >expect <<-\EOF &&
213 HEAD:fi:le:(1|2)d(3|4)
214 HEAD:su:b/fi:le:(1|2)d(3|4)
215 EOF
216 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD >actual &&
217 test_cmp expect actual
218 '
219
220 test_expect_success 'grep history with moved submoules' '
221 git init parent &&
222 test_when_finished "rm -rf parent" &&
223 echo "(1|2)d(3|4)" >parent/file &&
224 git -C parent add file &&
225 git -C parent commit -m "add file" &&
226 test_tick &&
227
228 git init sub &&
229 test_when_finished "rm -rf sub" &&
230 echo "(1|2)d(3|4)" >sub/file &&
231 git -C sub add file &&
232 git -C sub commit -m "add file" &&
233 test_tick &&
234
235 test_config_global protocol.file.allow always &&
236 git -C parent submodule add ../sub dir/sub &&
237 git -C parent commit -m "add submodule" &&
238 test_tick &&
239
240 cat >expect <<-\EOF &&
241 dir/sub/file:(1|2)d(3|4)
242 file:(1|2)d(3|4)
243 EOF
244 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
245 test_cmp expect actual &&
246
247 git -C parent mv dir/sub sub-moved &&
248 git -C parent commit -m "moved submodule" &&
249 test_tick &&
250
251 cat >expect <<-\EOF &&
252 file:(1|2)d(3|4)
253 sub-moved/file:(1|2)d(3|4)
254 EOF
255 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
256 test_cmp expect actual &&
257
258 cat >expect <<-\EOF &&
259 HEAD^:dir/sub/file:(1|2)d(3|4)
260 HEAD^:file:(1|2)d(3|4)
261 EOF
262 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD^ >actual &&
263 test_cmp expect actual
264 '
265
266 test_expect_success 'grep using relative path' '
267 test_when_finished "rm -rf parent sub" &&
268 git init sub &&
269 echo "(1|2)d(3|4)" >sub/file &&
270 git -C sub add file &&
271 git -C sub commit -m "add file" &&
272 test_tick &&
273
274 git init parent &&
275 echo "(1|2)d(3|4)" >parent/file &&
276 git -C parent add file &&
277 mkdir parent/src &&
278 echo "(1|2)d(3|4)" >parent/src/file2 &&
279 git -C parent add src/file2 &&
280 test_config_global protocol.file.allow always &&
281 git -C parent submodule add ../sub &&
282 git -C parent commit -m "add files and submodule" &&
283 test_tick &&
284
285 # From top works
286 cat >expect <<-\EOF &&
287 file:(1|2)d(3|4)
288 src/file2:(1|2)d(3|4)
289 sub/file:(1|2)d(3|4)
290 EOF
291 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
292 test_cmp expect actual &&
293
294 # Relative path to top
295 cat >expect <<-\EOF &&
296 ../file:(1|2)d(3|4)
297 file2:(1|2)d(3|4)
298 ../sub/file:(1|2)d(3|4)
299 EOF
300 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- .. >actual &&
301 test_cmp expect actual &&
302
303 # Relative path to submodule
304 cat >expect <<-\EOF &&
305 ../sub/file:(1|2)d(3|4)
306 EOF
307 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- ../sub >actual &&
308 test_cmp expect actual
309 '
310
311 test_expect_success 'grep from a subdir' '
312 test_when_finished "rm -rf parent sub" &&
313 git init sub &&
314 echo "(1|2)d(3|4)" >sub/file &&
315 git -C sub add file &&
316 git -C sub commit -m "add file" &&
317 test_tick &&
318
319 git init parent &&
320 mkdir parent/src &&
321 echo "(1|2)d(3|4)" >parent/src/file &&
322 git -C parent add src/file &&
323 test_config_global protocol.file.allow always &&
324 git -C parent submodule add ../sub src/sub &&
325 git -C parent submodule add ../sub sub &&
326 git -C parent commit -m "add files and submodules" &&
327 test_tick &&
328
329 # Verify grep from root works
330 cat >expect <<-\EOF &&
331 src/file:(1|2)d(3|4)
332 src/sub/file:(1|2)d(3|4)
333 sub/file:(1|2)d(3|4)
334 EOF
335 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
336 test_cmp expect actual &&
337
338 # Verify grep from a subdir works
339 cat >expect <<-\EOF &&
340 file:(1|2)d(3|4)
341 sub/file:(1|2)d(3|4)
342 EOF
343 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
344 test_cmp expect actual
345 '
346
347 test_incompatible_with_recurse_submodules ()
348 {
349 test_expect_success "--recurse-submodules and $1 are incompatible" "
350 test_must_fail git grep -e. --recurse-submodules $1 2>actual &&
351 test_grep 'not supported with --recurse-submodules' actual
352 "
353 }
354
355 test_incompatible_with_recurse_submodules --untracked
356
357 test_expect_success 'grep --recurse-submodules --no-index ignores --recurse-submodules' '
358 git grep --recurse-submodules --no-index -e "^(.|.)[\d]" >actual &&
359 cat >expect <<-\EOF &&
360 a:(1|2)d(3|4)
361 submodule/a:(1|2)d(3|4)
362 submodule/sub/a:(1|2)d(3|4)
363 EOF
364 test_cmp expect actual
365 '
366
367 test_expect_success 'grep --recurse-submodules should pass the pattern type along' '
368 # Fixed
369 test_must_fail git grep -F --recurse-submodules -e "(.|.)[\d]" &&
370 test_must_fail git -c grep.patternType=fixed grep --recurse-submodules -e "(.|.)[\d]" &&
371
372 # Basic
373 git grep -G --recurse-submodules -e "(.|.)[\d]" >actual &&
374 cat >expect <<-\EOF &&
375 a:(1|2)d(3|4)
376 submodule/a:(1|2)d(3|4)
377 submodule/sub/a:(1|2)d(3|4)
378 EOF
379 test_cmp expect actual &&
380 git -c grep.patternType=basic grep --recurse-submodules -e "(.|.)[\d]" >actual &&
381 test_cmp expect actual &&
382
383 # Extended
384 git grep -E --recurse-submodules -e "(.|.)[\d]" >actual &&
385 cat >expect <<-\EOF &&
386 .gitmodules:[submodule "submodule"]
387 .gitmodules: path = submodule
388 .gitmodules: url = ./submodule
389 a:(1|2)d(3|4)
390 submodule/.gitmodules:[submodule "sub"]
391 submodule/a:(1|2)d(3|4)
392 submodule/sub/a:(1|2)d(3|4)
393 EOF
394 test_cmp expect actual &&
395 git -c grep.patternType=extended grep --recurse-submodules -e "(.|.)[\d]" >actual &&
396 test_cmp expect actual &&
397 git -c grep.extendedRegexp=true grep --recurse-submodules -e "(.|.)[\d]" >actual &&
398 test_cmp expect actual &&
399
400 # Perl
401 if test_have_prereq PCRE
402 then
403 git grep -P --recurse-submodules -e "(.|.)[\d]" >actual &&
404 cat >expect <<-\EOF &&
405 a:(1|2)d(3|4)
406 b/b:(3|4)
407 submodule/a:(1|2)d(3|4)
408 submodule/sub/a:(1|2)d(3|4)
409 EOF
410 test_cmp expect actual &&
411 git -c grep.patternType=perl grep --recurse-submodules -e "(.|.)[\d]" >actual &&
412 test_cmp expect actual
413 fi
414 '
415
416 test_expect_success 'grep --recurse-submodules with submodules without .gitmodules in the working tree' '
417 test_when_finished "git -C submodule checkout .gitmodules" &&
418 rm submodule/.gitmodules &&
419 git grep --recurse-submodules -e "(.|.)[\d]" >actual &&
420 cat >expect <<-\EOF &&
421 a:(1|2)d(3|4)
422 submodule/a:(1|2)d(3|4)
423 submodule/sub/a:(1|2)d(3|4)
424 EOF
425 test_cmp expect actual
426 '
427
428 reset_and_clean () {
429 git reset --hard &&
430 git clean -fd &&
431 git submodule foreach --recursive 'git reset --hard' &&
432 git submodule foreach --recursive 'git clean -fd'
433 }
434
435 test_expect_success 'grep --recurse-submodules without --cached considers worktree modifications' '
436 reset_and_clean &&
437 echo "A modified line in submodule" >>submodule/a &&
438 echo "submodule/a:A modified line in submodule" >expect &&
439 git grep --recurse-submodules "A modified line in submodule" >actual &&
440 test_cmp expect actual
441 '
442
443 test_expect_success 'grep --recurse-submodules with --cached ignores worktree modifications' '
444 reset_and_clean &&
445 echo "A modified line in submodule" >>submodule/a &&
446 test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 &&
447 test_must_be_empty actual
448 '
449
450 test_expect_failure 'grep --textconv: superproject .gitattributes does not affect submodules' '
451 reset_and_clean &&
452 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
453 echo "a diff=d2x" >.gitattributes &&
454
455 cat >expect <<-\EOF &&
456 a:(1|2)x(3|4)
457 EOF
458 git grep --textconv --recurse-submodules x >actual &&
459 test_cmp expect actual
460 '
461
462 test_expect_failure 'grep --textconv: superproject .gitattributes (from index) does not affect submodules' '
463 reset_and_clean &&
464 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
465 echo "a diff=d2x" >.gitattributes &&
466 git add .gitattributes &&
467 rm .gitattributes &&
468
469 cat >expect <<-\EOF &&
470 a:(1|2)x(3|4)
471 EOF
472 git grep --textconv --recurse-submodules x >actual &&
473 test_cmp expect actual
474 '
475
476 test_expect_failure 'grep --textconv: superproject .git/info/attributes does not affect submodules' '
477 reset_and_clean &&
478 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
479 super_info="$(git rev-parse --git-path info)" &&
480 super_attr="$super_info/attributes" &&
481 test_when_finished "rm -f \"$super_attr\"" &&
482 mkdir "$super_info" &&
483 echo "a diff=d2x" >"$super_attr" &&
484
485 cat >expect <<-\EOF &&
486 a:(1|2)x(3|4)
487 EOF
488 git grep --textconv --recurse-submodules x >actual &&
489 test_cmp expect actual
490 '
491
492 # Note: what currently prevents this test from passing is not that the
493 # .gitattributes file from "./submodule" is being ignored, but that it is being
494 # propagated to the nested "./submodule/sub" files.
495 #
496 test_expect_failure 'grep --textconv correctly reads submodule .gitattributes' '
497 reset_and_clean &&
498 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
499 echo "a diff=d2x" >submodule/.gitattributes &&
500
501 cat >expect <<-\EOF &&
502 submodule/a:(1|2)x(3|4)
503 EOF
504 git grep --textconv --recurse-submodules x >actual &&
505 test_cmp expect actual
506 '
507
508 test_expect_failure 'grep --textconv correctly reads submodule .gitattributes (from index)' '
509 reset_and_clean &&
510 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
511 echo "a diff=d2x" >submodule/.gitattributes &&
512 git -C submodule add .gitattributes &&
513 rm submodule/.gitattributes &&
514
515 cat >expect <<-\EOF &&
516 submodule/a:(1|2)x(3|4)
517 EOF
518 git grep --textconv --recurse-submodules x >actual &&
519 test_cmp expect actual
520 '
521
522 test_expect_failure 'grep --textconv correctly reads submodule .git/info/attributes' '
523 reset_and_clean &&
524 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
525
526 submodule_info="$(git -C submodule rev-parse --path-format=absolute --git-path info)" &&
527 submodule_attr="$submodule_info/attributes" &&
528 test_when_finished "rm -f \"$submodule_attr\"" &&
529 echo "a diff=d2x" >"$submodule_attr" &&
530
531 cat >expect <<-\EOF &&
532 submodule/a:(1|2)x(3|4)
533 EOF
534 git grep --textconv --recurse-submodules x >actual &&
535 test_cmp expect actual
536 '
537
538 test_expect_failure 'grep saves textconv cache in the appropriate repository' '
539 reset_and_clean &&
540 test_config_global diff.d2x_cached.textconv "sed -e \"s/d/x/\"" &&
541 test_config_global diff.d2x_cached.cachetextconv true &&
542 echo "a diff=d2x_cached" >submodule/.gitattributes &&
543
544 # We only read/write to the textconv cache when grepping from an OID,
545 # as the working tree file might have modifications.
546 git grep --textconv --cached --recurse-submodules x &&
547
548 super_textconv_cache="$(git rev-parse --git-path refs/notes/textconv/d2x_cached)" &&
549 sub_textconv_cache="$(git -C submodule rev-parse \
550 --path-format=absolute --git-path refs/notes/textconv/d2x_cached)" &&
551 test_path_is_missing "$super_textconv_cache" &&
552 test_path_is_file "$sub_textconv_cache"
553 '
554
555 test_expect_success 'grep partially-cloned submodule' '
556 # Set up clean superproject and submodule for partial cloning.
557 test_config_global protocol.file.allow always &&
558 git init super &&
559 git init super/sub &&
560 (
561 cd super &&
562 test_commit --no-tag "Add file in superproject" \
563 super-file "Some content for super-file" &&
564 test_commit -C sub --no-tag "Add file in submodule" \
565 sub-file "Some content for sub-file" &&
566 git submodule add ./sub &&
567 git commit -m "Add other as submodule sub" &&
568 test_tick &&
569 test_commit -C sub --no-tag --append "Update file in submodule" \
570 sub-file "Some more content for sub-file" &&
571 git add sub &&
572 git commit -m "Update submodule" &&
573 test_tick &&
574 git config --local uploadpack.allowfilter 1 &&
575 git config --local uploadpack.allowanysha1inwant 1 &&
576 git -C sub config --local uploadpack.allowfilter 1 &&
577 git -C sub config --local uploadpack.allowanysha1inwant 1
578 ) &&
579 # Clone the superproject & submodule, then make sure we can lazy-fetch submodule objects.
580 git clone --filter=blob:none --also-filter-submodules \
581 --recurse-submodules "file://$(pwd)/super" partial &&
582 (
583 cd partial &&
584 cat >expect <<-\EOF &&
585 HEAD^:sub/sub-file:Some content for sub-file
586 HEAD^:super-file:Some content for super-file
587 EOF
588
589 GIT_TRACE2_EVENT="$(pwd)/trace2.log" git grep -e content \
590 --recurse-submodules HEAD^ >actual &&
591 test_cmp expect actual &&
592 # Verify that we actually fetched data from the promisor remote:
593 grep \"category\":\"promisor\",\"key\":\"fetch_count\",\"value\":\"1\" trace2.log
594 )
595 '
596
597 test_expect_success 'check scope of core.useReplaceRefs' '
598 git init base &&
599 git init base/sub &&
600
601 echo A >base/a &&
602 echo B >base/b &&
603 echo C >base/sub/c &&
604 echo D >base/sub/d &&
605
606 git -C base/sub add c d &&
607 git -C base/sub commit -m "Add files" &&
608
609 git -C base submodule add ./sub &&
610 git -C base add a b sub &&
611 git -C base commit -m "Add files and submodule" &&
612
613 A=$(git -C base rev-parse HEAD:a) &&
614 B=$(git -C base rev-parse HEAD:b) &&
615 C=$(git -C base/sub rev-parse HEAD:c) &&
616 D=$(git -C base/sub rev-parse HEAD:d) &&
617
618 git -C base replace $A $B &&
619 git -C base/sub replace $C $D &&
620
621 test_must_fail git -C base grep --cached --recurse-submodules A &&
622 test_must_fail git -C base grep --cached --recurse-submodules C &&
623
624 git -C base config core.useReplaceRefs false &&
625 git -C base grep --recurse-submodules A &&
626 test_must_fail git -C base grep --cached --recurse-submodules C &&
627
628 git -C base/sub config core.useReplaceRefs false &&
629 git -C base grep --cached --recurse-submodules A &&
630 git -C base grep --cached --recurse-submodules C &&
631
632 git -C base config --unset core.useReplaceRefs &&
633 test_must_fail git -C base grep --cached --recurse-submodules A &&
634 git -C base grep --cached --recurse-submodules C
635 '
636
637 test_done