]> git.proxmox.com Git - libgit2.git/blame - tests/filter/custom.c
Merge pull request #2273 from jacquesg/ssh-interactive
[libgit2.git] / tests / filter / custom.c
CommitLineData
b47349b8
RB
1#include "clar_libgit2.h"
2#include "posix.h"
3#include "blob.h"
4#include "filter.h"
5#include "buf_text.h"
6#include "git2/sys/filter.h"
7#include "git2/sys/repository.h"
8
eefc32d5
RB
9/* going TO_WORKDIR, filters are executed low to high
10 * going TO_ODB, filters are executed high to low
11 */
12#define BITFLIP_FILTER_PRIORITY -1
13#define REVERSE_FILTER_PRIORITY -2
b47349b8
RB
14
15#define VERY_SECURE_ENCRYPTION(b) ((b) ^ 0xff)
16
17#ifdef GIT_WIN32
18# define NEWLINE "\r\n"
19#else
20# define NEWLINE "\n"
21#endif
22
23static char workdir_data[] =
24 "some simple" NEWLINE
25 "data" NEWLINE
26 "that will be" NEWLINE
27 "trivially" NEWLINE
28 "scrambled." NEWLINE;
29
30/* Represents the data above scrambled (bits flipped) after \r\n -> \n
31 * conversion, then bytewise reversed
32 */
33static unsigned char bitflipped_and_reversed_data[] =
34 { 0xf5, 0xd1, 0x9b, 0x9a, 0x93, 0x9d, 0x92, 0x9e, 0x8d, 0x9c, 0x8c,
35 0xf5, 0x86, 0x93, 0x93, 0x9e, 0x96, 0x89, 0x96, 0x8d, 0x8b, 0xf5,
36 0x9a, 0x9d, 0xdf, 0x93, 0x93, 0x96, 0x88, 0xdf, 0x8b, 0x9e, 0x97,
37 0x8b, 0xf5, 0x9e, 0x8b, 0x9e, 0x9b, 0xf5, 0x9a, 0x93, 0x8f, 0x92,
38 0x96, 0x8c, 0xdf, 0x9a, 0x92, 0x90, 0x8c };
39
40#define BITFLIPPED_AND_REVERSED_DATA_LEN 51
41
42static git_repository *g_repo = NULL;
43
44static void register_custom_filters(void);
45
46void test_filter_custom__initialize(void)
47{
48 register_custom_filters();
49
50 g_repo = cl_git_sandbox_init("empty_standard_repo");
51
52 cl_git_mkfile(
53 "empty_standard_repo/.gitattributes",
54 "hero* bitflip reverse\n"
55 "herofile text\n"
ad7417d7
RB
56 "heroflip -reverse binary\n"
57 "*.bin binary\n");
b47349b8
RB
58}
59
60void test_filter_custom__cleanup(void)
61{
62 cl_git_sandbox_cleanup();
63 g_repo = NULL;
64}
65
66static int bitflip_filter_apply(
67 git_filter *self,
68 void **payload,
69 git_buf *to,
70 const git_buf *from,
71 const git_filter_source *source)
72{
73 const unsigned char *src = (const unsigned char *)from->ptr;
74 unsigned char *dst;
75 size_t i;
76
77 GIT_UNUSED(self); GIT_UNUSED(payload);
78
79 /* verify that attribute path match worked as expected */
80 cl_assert_equal_i(
81 0, git__strncmp("hero", git_filter_source_path(source), 4));
82
83 if (!from->size)
84 return 0;
85
86 cl_git_pass(git_buf_grow(to, from->size));
87
88 dst = (unsigned char *)to->ptr;
89
90 for (i = 0; i < from->size; i++)
91 dst[i] = VERY_SECURE_ENCRYPTION(src[i]);
92
93 to->size = from->size;
94
95 return 0;
96}
97
98static void bitflip_filter_free(git_filter *f)
99{
100 git__free(f);
101}
102
103static git_filter *create_bitflip_filter(void)
104{
105 git_filter *filter = git__calloc(1, sizeof(git_filter));
106 cl_assert(filter);
107
108 filter->version = GIT_FILTER_VERSION;
109 filter->attributes = "+bitflip";
110 filter->shutdown = bitflip_filter_free;
111 filter->apply = bitflip_filter_apply;
112
113 return filter;
114}
115
116
117static int reverse_filter_apply(
118 git_filter *self,
119 void **payload,
120 git_buf *to,
121 const git_buf *from,
122 const git_filter_source *source)
123{
124 const unsigned char *src = (const unsigned char *)from->ptr;
125 const unsigned char *end = src + from->size;
126 unsigned char *dst;
127
128 GIT_UNUSED(self); GIT_UNUSED(payload); GIT_UNUSED(source);
129
130 /* verify that attribute path match worked as expected */
131 cl_assert_equal_i(
132 0, git__strncmp("hero", git_filter_source_path(source), 4));
133
134 if (!from->size)
135 return 0;
136
137 cl_git_pass(git_buf_grow(to, from->size));
138
139 dst = (unsigned char *)to->ptr + from->size - 1;
140
141 while (src < end)
142 *dst-- = *src++;
143
144 to->size = from->size;
145
146 return 0;
147}
148
149static void reverse_filter_free(git_filter *f)
150{
151 git__free(f);
152}
153
eefc32d5 154static git_filter *create_reverse_filter(const char *attrs)
b47349b8
RB
155{
156 git_filter *filter = git__calloc(1, sizeof(git_filter));
157 cl_assert(filter);
158
159 filter->version = GIT_FILTER_VERSION;
eefc32d5 160 filter->attributes = attrs;
b47349b8
RB
161 filter->shutdown = reverse_filter_free;
162 filter->apply = reverse_filter_apply;
163
164 return filter;
165}
166
167static void register_custom_filters(void)
168{
169 static int filters_registered = 0;
170
171 if (!filters_registered) {
172 cl_git_pass(git_filter_register(
173 "bitflip", create_bitflip_filter(), BITFLIP_FILTER_PRIORITY));
174
175 cl_git_pass(git_filter_register(
eefc32d5
RB
176 "reverse", create_reverse_filter("+reverse"),
177 REVERSE_FILTER_PRIORITY));
178
179 /* re-register reverse filter with standard filter=xyz priority */
180 cl_git_pass(git_filter_register(
181 "pre-reverse",
182 create_reverse_filter("+prereverse"),
183 GIT_FILTER_DRIVER_PRIORITY));
b47349b8
RB
184
185 filters_registered = 1;
186 }
187}
188
189
190void test_filter_custom__to_odb(void)
191{
192 git_filter_list *fl;
193 git_buf out = { 0 };
194 git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data));
195
196 cl_git_pass(git_filter_list_load(
197 &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_ODB));
198
199 cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
200
201 cl_assert_equal_i(BITFLIPPED_AND_REVERSED_DATA_LEN, out.size);
202
203 cl_assert_equal_i(
204 0, memcmp(bitflipped_and_reversed_data, out.ptr, out.size));
205
206 git_filter_list_free(fl);
207 git_buf_free(&out);
208}
209
210void test_filter_custom__to_workdir(void)
211{
212 git_filter_list *fl;
213 git_buf out = { 0 };
214 git_buf in = GIT_BUF_INIT_CONST(
215 bitflipped_and_reversed_data, BITFLIPPED_AND_REVERSED_DATA_LEN);
216
217 cl_git_pass(git_filter_list_load(
218 &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE));
219
220 cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
221
222 cl_assert_equal_i(strlen(workdir_data), out.size);
223
224 cl_assert_equal_i(
225 0, memcmp(workdir_data, out.ptr, out.size));
226
227 git_filter_list_free(fl);
228 git_buf_free(&out);
229}
230
231void test_filter_custom__can_register_a_custom_filter_in_the_repository(void)
232{
233 git_filter_list *fl;
234
235 cl_git_pass(git_filter_list_load(
236 &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE));
237 /* expect: bitflip, reverse, crlf */
238 cl_assert_equal_sz(3, git_filter_list_length(fl));
239 git_filter_list_free(fl);
240
241 cl_git_pass(git_filter_list_load(
242 &fl, g_repo, NULL, "herocorp", GIT_FILTER_TO_WORKTREE));
ad7417d7
RB
243 /* expect: bitflip, reverse - possibly crlf depending on global config */
244 {
245 size_t flen = git_filter_list_length(fl);
246 cl_assert(flen == 2 || flen == 3);
247 }
248 git_filter_list_free(fl);
249
250 cl_git_pass(git_filter_list_load(
251 &fl, g_repo, NULL, "hero.bin", GIT_FILTER_TO_WORKTREE));
b47349b8
RB
252 /* expect: bitflip, reverse */
253 cl_assert_equal_sz(2, git_filter_list_length(fl));
254 git_filter_list_free(fl);
255
256 cl_git_pass(git_filter_list_load(
257 &fl, g_repo, NULL, "heroflip", GIT_FILTER_TO_WORKTREE));
258 /* expect: bitflip (because of -reverse) */
259 cl_assert_equal_sz(1, git_filter_list_length(fl));
260 git_filter_list_free(fl);
261
262 cl_git_pass(git_filter_list_load(
ad7417d7 263 &fl, g_repo, NULL, "doesntapplytome.bin", GIT_FILTER_TO_WORKTREE));
b47349b8
RB
264 /* expect: none */
265 cl_assert_equal_sz(0, git_filter_list_length(fl));
266 git_filter_list_free(fl);
267}
eab3746b
RB
268
269void test_filter_custom__order_dependency(void)
270{
271 git_index *index;
272 git_blob *blob;
273 git_buf buf = { 0 };
274
275 /* so if ident and reverse are used together, an interesting thing
276 * happens - a reversed "$Id$" string is no longer going to trigger
277 * ident correctly. When checking out, the filters should be applied
278 * in order CLRF, then ident, then reverse, so ident expansion should
279 * work correctly. On check in, the content should be reversed, then
280 * ident, then CRLF filtered. Let's make sure that works...
281 */
282
283 cl_git_mkfile(
284 "empty_standard_repo/.gitattributes",
eefc32d5 285 "hero.*.rev-ident text ident prereverse eol=lf\n");
eab3746b
RB
286
287 cl_git_mkfile(
288 "empty_standard_repo/hero.1.rev-ident",
289 "This is a test\n$Id$\nHave fun!\n");
290
291 cl_git_mkfile(
292 "empty_standard_repo/hero.2.rev-ident",
293 "Another test\n$dI$\nCrazy!\n");
294
295 cl_git_pass(git_repository_index(&index, g_repo));
296 cl_git_pass(git_index_add_bypath(index, "hero.1.rev-ident"));
297 cl_git_pass(git_index_add_bypath(index, "hero.2.rev-ident"));
298 cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "Filter chains\n");
299 git_index_free(index);
300
301 cl_git_pass(git_blob_lookup(&blob, g_repo,
d541170c 302 & git_index_get_bypath(index, "hero.1.rev-ident", 0)->id));
eab3746b
RB
303 cl_assert_equal_s(
304 "\n!nuf evaH\n$dI$\ntset a si sihT", git_blob_rawcontent(blob));
305 cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.1.rev-ident", 0));
306 /* no expansion because id was reversed at checkin and now at ident
307 * time, reverse is not applied yet */
308 cl_assert_equal_s(
309 "This is a test\n$Id$\nHave fun!\n", buf.ptr);
310 git_blob_free(blob);
311
312 cl_git_pass(git_blob_lookup(&blob, g_repo,
d541170c 313 & git_index_get_bypath(index, "hero.2.rev-ident", 0)->id));
eab3746b
RB
314 cl_assert_equal_s(
315 "\n!yzarC\n$Id$\ntset rehtonA", git_blob_rawcontent(blob));
316 cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.2.rev-ident", 0));
317 /* expansion because reverse was applied at checkin and at ident time,
318 * reverse is not applied yet */
319 cl_assert_equal_s(
320 "Another test\n$59001fe193103b1016b27027c0c827d036fd0ac8 :dI$\nCrazy!\n", buf.ptr);
321 cl_assert_equal_i(0, git_oid_strcmp(
322 git_blob_id(blob), "8ca0df630d728c0c72072b6101b301391ef10095"));
323 git_blob_free(blob);
324
325 git_buf_free(&buf);
326}
eefc32d5
RB
327
328void test_filter_custom__filter_registry_failure_cases(void)
329{
330 git_filter fake = { GIT_FILTER_VERSION, 0 };
331
332 cl_assert_equal_i(GIT_EEXISTS, git_filter_register("bitflip", &fake, 0));
333
334 cl_git_fail(git_filter_unregister(GIT_FILTER_CRLF));
335 cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT));
336 cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter"));
337}