#include "clar_libgit2.h" #include "posix.h" #include "blob.h" #include "filter.h" #include "buf_text.h" #include "git2/sys/filter.h" #include "git2/sys/repository.h" #include "custom_helpers.h" /* going TO_WORKDIR, filters are executed low to high * going TO_ODB, filters are executed high to low */ #define BITFLIP_FILTER_PRIORITY -1 #define REVERSE_FILTER_PRIORITY -2 #ifdef GIT_WIN32 # define NEWLINE "\r\n" #else # define NEWLINE "\n" #endif static char workdir_data[] = "some simple" NEWLINE "data" NEWLINE "that will be" NEWLINE "trivially" NEWLINE "scrambled." NEWLINE; #define REVERSED_DATA_LEN 51 /* Represents the data above scrambled (bits flipped) after \r\n -> \n * conversion, then bytewise reversed */ static unsigned char bitflipped_and_reversed_data[] = { 0xf5, 0xd1, 0x9b, 0x9a, 0x93, 0x9d, 0x92, 0x9e, 0x8d, 0x9c, 0x8c, 0xf5, 0x86, 0x93, 0x93, 0x9e, 0x96, 0x89, 0x96, 0x8d, 0x8b, 0xf5, 0x9a, 0x9d, 0xdf, 0x93, 0x93, 0x96, 0x88, 0xdf, 0x8b, 0x9e, 0x97, 0x8b, 0xf5, 0x9e, 0x8b, 0x9e, 0x9b, 0xf5, 0x9a, 0x93, 0x8f, 0x92, 0x96, 0x8c, 0xdf, 0x9a, 0x92, 0x90, 0x8c }; #define BITFLIPPED_AND_REVERSED_DATA_LEN 51 static git_repository *g_repo = NULL; static void register_custom_filters(void); void test_filter_custom__initialize(void) { register_custom_filters(); g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_git_mkfile( "empty_standard_repo/.gitattributes", "hero* bitflip reverse\n" "herofile text\n" "heroflip -reverse binary\n" "villain erroneous\n" "*.bin binary\n"); } void test_filter_custom__cleanup(void) { cl_git_sandbox_cleanup(); g_repo = NULL; } static void register_custom_filters(void) { static int filters_registered = 0; if (!filters_registered) { cl_git_pass(git_filter_register( "bitflip", create_bitflip_filter(), BITFLIP_FILTER_PRIORITY)); cl_git_pass(git_filter_register( "reverse", create_reverse_filter("+reverse"), REVERSE_FILTER_PRIORITY)); /* re-register reverse filter with standard filter=xyz priority */ cl_git_pass(git_filter_register( "pre-reverse", create_reverse_filter("+prereverse"), GIT_FILTER_DRIVER_PRIORITY)); cl_git_pass(git_filter_register( "erroneous", create_erroneous_filter("+erroneous"), GIT_FILTER_DRIVER_PRIORITY)); filters_registered = 1; } } void test_filter_custom__to_odb(void) { git_filter_list *fl; git_buf out = { 0 }; git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data)); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_ODB, 0)); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(BITFLIPPED_AND_REVERSED_DATA_LEN, out.size); cl_assert_equal_i( 0, memcmp(bitflipped_and_reversed_data, out.ptr, out.size)); git_filter_list_free(fl); git_buf_free(&out); } void test_filter_custom__to_workdir(void) { git_filter_list *fl; git_buf out = { 0 }; git_buf in = GIT_BUF_INIT_CONST( bitflipped_and_reversed_data, BITFLIPPED_AND_REVERSED_DATA_LEN); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE, 0)); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(strlen(workdir_data), out.size); cl_assert_equal_i( 0, memcmp(workdir_data, out.ptr, out.size)); git_filter_list_free(fl); git_buf_free(&out); } void test_filter_custom__can_register_a_custom_filter_in_the_repository(void) { git_filter_list *fl; cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE, 0)); /* expect: bitflip, reverse, crlf */ cl_assert_equal_sz(3, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herocorp", GIT_FILTER_TO_WORKTREE, 0)); /* expect: bitflip, reverse - possibly crlf depending on global config */ { size_t flen = git_filter_list_length(fl); cl_assert(flen == 2 || flen == 3); } git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "hero.bin", GIT_FILTER_TO_WORKTREE, 0)); /* expect: bitflip, reverse */ cl_assert_equal_sz(2, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "heroflip", GIT_FILTER_TO_WORKTREE, 0)); /* expect: bitflip (because of -reverse) */ cl_assert_equal_sz(1, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "doesntapplytome.bin", GIT_FILTER_TO_WORKTREE, 0)); /* expect: none */ cl_assert_equal_sz(0, git_filter_list_length(fl)); git_filter_list_free(fl); } void test_filter_custom__order_dependency(void) { git_index *index; git_blob *blob; git_buf buf = { 0 }; /* so if ident and reverse are used together, an interesting thing * happens - a reversed "$Id$" string is no longer going to trigger * ident correctly. When checking out, the filters should be applied * in order CLRF, then ident, then reverse, so ident expansion should * work correctly. On check in, the content should be reversed, then * ident, then CRLF filtered. Let's make sure that works... */ cl_git_mkfile( "empty_standard_repo/.gitattributes", "hero.*.rev-ident text ident prereverse eol=lf\n"); cl_git_mkfile( "empty_standard_repo/hero.1.rev-ident", "This is a test\n$Id$\nHave fun!\n"); cl_git_mkfile( "empty_standard_repo/hero.2.rev-ident", "Another test\n$dI$\nCrazy!\n"); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_add_bypath(index, "hero.1.rev-ident")); cl_git_pass(git_index_add_bypath(index, "hero.2.rev-ident")); cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "Filter chains\n"); git_index_free(index); cl_git_pass(git_blob_lookup(&blob, g_repo, & git_index_get_bypath(index, "hero.1.rev-ident", 0)->id)); cl_assert_equal_s( "\n!nuf evaH\n$dI$\ntset a si sihT", git_blob_rawcontent(blob)); cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.1.rev-ident", 0)); /* no expansion because id was reversed at checkin and now at ident * time, reverse is not applied yet */ cl_assert_equal_s( "This is a test\n$Id$\nHave fun!\n", buf.ptr); git_blob_free(blob); cl_git_pass(git_blob_lookup(&blob, g_repo, & git_index_get_bypath(index, "hero.2.rev-ident", 0)->id)); cl_assert_equal_s( "\n!yzarC\n$Id$\ntset rehtonA", git_blob_rawcontent(blob)); cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.2.rev-ident", 0)); /* expansion because reverse was applied at checkin and at ident time, * reverse is not applied yet */ cl_assert_equal_s( "Another test\n$ 59001fe193103b1016b27027c0c827d036fd0ac8 :dI$\nCrazy!\n", buf.ptr); cl_assert_equal_i(0, git_oid_strcmp( git_blob_id(blob), "8ca0df630d728c0c72072b6101b301391ef10095")); git_blob_free(blob); git_buf_free(&buf); } void test_filter_custom__filter_registry_failure_cases(void) { git_filter fake = { GIT_FILTER_VERSION, 0 }; cl_assert_equal_i(GIT_EEXISTS, git_filter_register("bitflip", &fake, 0)); cl_git_fail(git_filter_unregister(GIT_FILTER_CRLF)); cl_git_fail(git_filter_unregister(GIT_FILTER_IDENT)); cl_assert_equal_i(GIT_ENOTFOUND, git_filter_unregister("not-a-filter")); } void test_filter_custom__erroneous_filter_fails(void) { git_filter_list *filters; git_buf out = GIT_BUF_INIT; git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data)); cl_git_pass(git_filter_list_load( &filters, g_repo, NULL, "villain", GIT_FILTER_TO_WORKTREE, 0)); cl_git_fail(git_filter_list_apply_to_data(&out, filters, &in)); git_filter_list_free(filters); git_buf_free(&out); }