summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-08-26 23:17:07 -0700
committerRussell Belfer <rb@github.com>2013-09-17 09:30:06 -0700
commit0cf77103b218ad3622aff34f3296db1bdd5f0df9 (patch)
treef60998088c2617f3a289942d7928112f0fe683e9
parent4581f9d8ab72e9b97817e1eaa7154bcec1c7f0b1 (diff)
downloadlibgit2-0cf77103b218ad3622aff34f3296db1bdd5f0df9.tar.gz
Start of filter API + git_blob_filtered_content
This begins the process of exposing git_filter objects to the public API. This includes: * new public type and API for `git_buffer` through which an allocated buffer can be passed to the user * new API `git_blob_filtered_content` * make the git_filter type and GIT_FILTER_TO_... constants public
-rw-r--r--include/git2.h3
-rw-r--r--include/git2/blob.h32
-rw-r--r--include/git2/buffer.h86
-rw-r--r--include/git2/filter.h54
-rw-r--r--src/blob.c51
-rw-r--r--src/buf_text.c19
-rw-r--r--src/buf_text.h8
-rw-r--r--src/buffer.c54
-rw-r--r--src/crlf.c20
-rw-r--r--src/filter.h19
-rw-r--r--tests-clar/checkout/crlf.c11
-rw-r--r--tests-clar/core/buffer.c47
-rw-r--r--tests-clar/filter/blob.c43
-rw-r--r--tests-clar/filter/crlf.h26
14 files changed, 428 insertions, 45 deletions
diff --git a/include/git2.h b/include/git2.h
index e8638a830..73c11ad83 100644
--- a/include/git2.h
+++ b/include/git2.h
@@ -58,4 +58,7 @@
#include "git2/stash.h"
#include "git2/pathspec.h"
+#include "git2/buffer.h"
+#include "git2/filter.h"
+
#endif
diff --git a/include/git2/blob.h b/include/git2/blob.h
index 8fca48966..dcb815b2f 100644
--- a/include/git2/blob.h
+++ b/include/git2/blob.h
@@ -11,6 +11,7 @@
#include "types.h"
#include "oid.h"
#include "object.h"
+#include "buffer.h"
/**
* @file git2/blob.h
@@ -96,6 +97,37 @@ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob);
GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob);
/**
+ * Get a buffer with the filtered content of a blob.
+ *
+ * This applies filters as if the blob was being checked out to the
+ * working directory under the specified filename. This may apply
+ * CRLF filtering or other types of changes depending on the file
+ * attributes set for the blob and the content detected in it.
+ *
+ * The output is written into a `git_buffer` which the caller must free
+ * when done (via `git_buffer_free`).
+ *
+ * If no filters need to be applied, then the `out` buffer will just be
+ * populated with a pointer to the raw content of the blob. In that case,
+ * be careful to *not* free the blob until done with the buffer. To keep
+ * the data detached from the blob, call `git_buffer_resize` on the buffer
+ * with a `want_size` of 0 and the buffer will be reallocated to be
+ * detached from the blob.
+ *
+ * @param out The git_buffer to be filled in
+ * @param blob Pointer to the blob
+ * @param as_path Path used for file attribute lookups, etc.
+ * @param check_for_binary_data Should this test if blob content contains
+ * NUL bytes / looks like binary data before applying filters?
+ * @return 0 on success or an error code
+ */
+GIT_EXTERN(int) git_blob_filtered_content(
+ git_buffer *out,
+ git_blob *blob,
+ const char *as_path,
+ int check_for_binary_data);
+
+/**
* Read a file from the working folder of a repository
* and write it to the Object Database as a loose blob
*
diff --git a/include/git2/buffer.h b/include/git2/buffer.h
new file mode 100644
index 000000000..454a1faa5
--- /dev/null
+++ b/include/git2/buffer.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_buffer_h__
+#define INCLUDE_git_buffer_h__
+
+#include "common.h"
+
+/**
+ * @file git2/buffer.h
+ * @brief Buffer export structure
+ *
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * A data buffer for exporting data from libgit2
+ *
+ * There are a number of places where libgit2 wants to return an allocated
+ * data buffer to the caller and have the caller take ownership of that
+ * allocated memory. This can be awkward if the caller does not have easy
+ * access to the same allocation functions that libgit2 is using. In those
+ * cases, libgit2 will instead fill in a `git_buffer` and the caller can
+ * use `git_buffer_free()` to release it when they are done.
+ *
+ * * `ptr` refers to the start of the allocated memory.
+ * * `size` contains the size of the data in `ptr` that is actually used.
+ * * `available` refers to the known total amount of allocated memory in
+ * cases where it is larger than the `size` actually in use.
+ *
+ * In a few cases, for uniformity and simplicity, an API may populate a
+ * `git_buffer` with data that should *not* be freed (i.e. the lifetime of
+ * the data buffer is actually tied to another libgit2 object). These
+ * cases will be clearly documented in the APIs that use the `git_buffer`.
+ * In those cases, the `available` field will be set to zero even though
+ * the `ptr` and `size` will be valid.
+ */
+typedef struct git_buffer {
+ char *ptr;
+ size_t size;
+ size_t available;
+} git_buffer;
+
+/**
+ * Use to initialize buffer structure when git_buffer is on stack
+ */
+#define GIT_BUFFER_INIT { NULL, 0, 0 }
+
+/**
+ * Free the memory referred to by the git_buffer.
+ *
+ * Note that this does not free the `git_buffer` itself, just the memory
+ * pointed to by `buffer->ptr`. If that memory was not allocated by
+ * libgit2 itself, be careful with using this function because it could
+ * cause problems.
+ *
+ * @param buffer The buffer with allocated memory
+ */
+GIT_EXTERN(void) git_buffer_free(git_buffer *buffer);
+
+/**
+ * Resize the buffer allocation to make more space.
+ *
+ * This will update `buffer->available` with the new size (which will be
+ * at least `want_size` and may be larger). This may or may not change
+ * `buffer->ptr` depending on whether there is an existing allocation and
+ * whether that allocation can be increased in place.
+ *
+ * Currently, this will never shrink the buffer, only expand it.
+ *
+ * @param buffer The buffer to be resized; may or may not be allocated yet
+ * @param want_size The desired available size
+ * @return 0 on success, negative error code on allocation failure
+ */
+GIT_EXTERN(int) git_buffer_resize(git_buffer *buffer, size_t want_size);
+
+GIT_END_DECL
+
+/** @} */
+
+#endif
diff --git a/include/git2/filter.h b/include/git2/filter.h
new file mode 100644
index 000000000..3bc4a9037
--- /dev/null
+++ b/include/git2/filter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_filter_h__
+#define INCLUDE_git_filter_h__
+
+#include "common.h"
+#include "types.h"
+#include "oid.h"
+#include "buffer.h"
+
+/**
+ * @file git2/filter.h
+ * @brief Git filter APIs
+ *
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Filters are applied in one of two directions: smudging - which is
+ * exporting a file from the Git object database to the working directory,
+ * and cleaning - which is importing a file from the working directory to
+ * the Git object database. These values control which direction of
+ * change is being applied.
+ */
+typedef enum {
+ GIT_FILTER_SMUDGE = 0,
+ GIT_FILTER_TO_WORKTREE = GIT_FILTER_SMUDGE,
+ GIT_FILTER_CLEAN = 1,
+ GIT_FILTER_TO_ODB = GIT_FILTER_CLEAN,
+} git_filter_mode_t;
+
+/**
+ * A filter that can transform file data
+ *
+ * This represents a filter that can be used to transform or even replace
+ * file data. Libgit2 currently includes one built in filter:
+ *
+ * * "crlf" which uses the complex rules with the "text", "eol", and
+ * "crlf" file attributes to decide how to convert between LF and CRLF
+ * line endings
+ */
+typedef struct git_filter git_filter;
+
+GIT_END_DECL
+
+/** @} */
+
+#endif
diff --git a/src/blob.c b/src/blob.c
index 6a289f43b..6a866538c 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -338,3 +338,54 @@ int git_blob_is_binary(git_blob *blob)
return git_buf_text_is_binary(&content);
}
+
+int git_blob_filtered_content(
+ git_buffer *out,
+ git_blob *blob,
+ const char *as_path,
+ int check_for_binary_data)
+{
+ int error = 0, num_filters = 0;
+ git_buf filtered = GIT_BUF_INIT, unfiltered = GIT_BUF_INIT;
+ git_vector filters = GIT_VECTOR_INIT;
+
+ assert(blob && as_path && out);
+
+ /* Create a fake git_buf from the blob raw data... */
+ filtered.ptr = (void *)git_blob_rawcontent(blob);
+ filtered.size = (size_t)git_blob_rawsize(blob);
+ filtered.asize = 0;
+
+ if (check_for_binary_data && git_buf_text_is_binary(&filtered))
+ return 0;
+
+ num_filters = git_filters_load(
+ &filters, git_blob_owner(blob), as_path, GIT_FILTER_TO_WORKTREE);
+ if (num_filters < 0)
+ return num_filters;
+
+ if (num_filters > 0) {
+ if (out->ptr && out->available) {
+ filtered.ptr = out->ptr;
+ filtered.size = out->size;
+ filtered.asize = out->available;
+ } else {
+ git_buf_init(&filtered, filtered.size + 1);
+ }
+
+ if (!(error = git_blob__getbuf(&unfiltered, blob)))
+ error = git_filters_apply(&filtered, &unfiltered, &filters);
+
+ git_filters_free(&filters);
+ git_buf_free(&unfiltered);
+ }
+
+ if (!error) {
+ out->ptr = filtered.ptr;
+ out->size = filtered.size;
+ out->available = filtered.asize;
+ }
+
+ return error;
+}
+
diff --git a/src/buf_text.c b/src/buf_text.c
index ecf592b51..eda86adb3 100644
--- a/src/buf_text.c
+++ b/src/buf_text.c
@@ -70,10 +70,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
assert(tgt != src);
if (!next)
- return GIT_ENOTFOUND;
+ return git_buf_set(tgt, src->ptr, src->size);
/* reduce reallocs while in the loop */
- if (git_buf_grow(tgt, src->size) < 0)
+ if (git_buf_grow(tgt, src->size + 1) < 0)
return -1;
out = tgt->ptr;
tgt->size = 0;
@@ -81,7 +81,7 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
/* Find the next \r and copy whole chunk up to there to tgt */
for (; next; scan = next + 1, next = memchr(scan, '\r', scan_end - scan)) {
if (next > scan) {
- size_t copylen = next - scan;
+ size_t copylen = (size_t)(next - scan);
memcpy(out, scan, copylen);
out += copylen;
}
@@ -92,9 +92,14 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
}
/* Copy remaining input into dest */
- memcpy(out, scan, scan_end - scan + 1); /* +1 for NUL byte */
- out += (scan_end - scan);
- tgt->size = out - tgt->ptr;
+ if (scan < scan_end) {
+ size_t remaining = (size_t)(scan_end - scan);
+ memcpy(out, scan, remaining);
+ out += remaining;
+ }
+
+ tgt->size = (size_t)(out - tgt->ptr);
+ tgt->ptr[tgt->size] = '\0';
return 0;
}
@@ -109,7 +114,7 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
assert(tgt != src);
if (!next)
- return GIT_ENOTFOUND;
+ return git_buf_set(tgt, src->ptr, src->size);
/* attempt to reduce reallocs while in the loop */
if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0)
diff --git a/src/buf_text.h b/src/buf_text.h
index 58e4e26a7..3ac9d1443 100644
--- a/src/buf_text.h
+++ b/src/buf_text.h
@@ -56,16 +56,16 @@ GIT_INLINE(int) git_buf_text_puts_escape_regex(git_buf *buf, const char *string)
extern void git_buf_text_unescape(git_buf *buf);
/**
- * Replace all \r\n with \n (or do nothing if no \r\n are found)
+ * Replace all \r\n with \n. Does not modify \r without trailing \n.
*
- * @return 0 on success, GIT_ENOTFOUND if no \r\n, -1 on memory error
+ * @return 0 on success, -1 on memory error
*/
extern int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src);
/**
- * Replace all \n with \r\n (or do nothing if no \n are found)
+ * Replace all \n with \r\n. Does not modify existing \r\n.
*
- * @return 0 on success, GIT_ENOTFOUND if no \n, -1 on memory error
+ * @return 0 on success, -1 on memory error
*/
extern int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src);
diff --git a/src/buffer.c b/src/buffer.c
index b5b2fd678..a92133674 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -6,6 +6,7 @@
*/
#include "buffer.h"
#include "posix.h"
+#include "git2/buffer.h"
#include <stdarg.h>
#include <ctype.h>
@@ -484,3 +485,56 @@ int git_buf_splice(
buf->ptr[buf->size] = '\0';
return 0;
}
+
+/*
+ * Public buffers API
+ */
+
+void git_buffer_free(git_buffer *buffer)
+{
+ if (!buffer)
+ return;
+
+ if (buffer->ptr != NULL && buffer->available > 0)
+ git__free(buffer->ptr);
+
+ git__memzero(buffer, sizeof(*buffer));
+}
+
+int git_buffer_resize(git_buffer *buffer, size_t want_size)
+{
+ int non_allocated_buffer = 0;
+ char *new_ptr;
+
+ assert(buffer);
+
+ /* check if buffer->ptr points to memory owned elsewhere */
+ non_allocated_buffer = (buffer->ptr != NULL && buffer->available == 0);
+
+ if (non_allocated_buffer && !want_size)
+ want_size = buffer->size;
+
+ if (buffer->available <= want_size)
+ return 0;
+
+ if (non_allocated_buffer) {
+ new_ptr = NULL;
+ if (want_size < buffer->size)
+ want_size = buffer->size;
+ } else {
+ new_ptr = buffer->ptr;
+ }
+
+ want_size = (want_size + 7) & ~7; /* round up to multiple of 8 */
+
+ new_ptr = git__realloc(new_ptr, want_size);
+ GITERR_CHECK_ALLOC(new_ptr);
+
+ if (non_allocated_buffer)
+ memcpy(new_ptr, buffer->ptr, buffer->size);
+
+ buffer->ptr = new_ptr;
+ buffer->available = want_size;
+
+ return 0;
+}
diff --git a/src/crlf.c b/src/crlf.c
index 65039f9cc..fbb3ba2dd 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -235,32 +235,36 @@ line_ending_error:
}
static int crlf_apply_to_workdir(
- git_filter *self, git_buf *dest, const git_buf *source)
+ git_filter *self, git_buf *tgt, const git_buf *src)
{
struct crlf_filter *filter = (struct crlf_filter *)self;
const char *workdir_ending = NULL;
- assert(self && dest && source);
+ assert(self && tgt && src);
/* Empty file? Nothing to do. */
- if (git_buf_len(source) == 0)
+ if (git_buf_len(src) == 0)
return -1;
/* Determine proper line ending */
workdir_ending = line_ending(filter);
if (!workdir_ending)
return -1;
- if (!strcmp("\n", workdir_ending)) /* do nothing for \n ending */
- return -1;
- /* for now, only lf->crlf conversion is supported here */
+ if (!strcmp("\n", workdir_ending)) {
+ if (git_buf_find(src, '\r') < 0)
+ return -1;
+ return git_buf_text_crlf_to_lf(tgt, src);
+ }
+
+ /* only other supported option is lf->crlf conversion */
assert(!strcmp("\r\n", workdir_ending));
- return git_buf_text_lf_to_crlf(dest, source);
+ return git_buf_text_lf_to_crlf(tgt, src);
}
static int find_and_add_filter(
git_vector *filters, git_repository *repo, const char *path,
- int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source))
+ int (*apply)(struct git_filter *self, git_buf *tgt, const git_buf *src))
{
struct crlf_attrs ca;
struct crlf_filter *filter;
diff --git a/src/filter.h b/src/filter.h
index 42a44ebdb..67845ad6a 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -11,16 +11,12 @@
#include "buffer.h"
#include "git2/odb.h"
#include "git2/repository.h"
+#include "git2/filter.h"
-typedef struct git_filter {
+struct git_filter {
int (*apply)(struct git_filter *self, git_buf *dest, const git_buf *source);
void (*do_free)(struct git_filter *self);
-} git_filter;
-
-typedef enum {
- GIT_FILTER_TO_WORKTREE,
- GIT_FILTER_TO_ODB
-} git_filter_mode;
+};
typedef enum {
GIT_CRLF_GUESS = -1,
@@ -60,13 +56,14 @@ extern int git_filters_load(git_vector *filters, git_repository *repo, const cha
* and `dest` buffers are owned by the caller and must be freed once
* they are no longer needed.
*
- * NOTE: Because of the double-buffering schema, the `source` buffer that contains
- * the original file may be tampered once the filtering is complete. Regardless,
- * the `dest` buffer will always contain the final result of the filtering
+ * NOTE: Because of the double-buffering schema, the `source` buffer that
+ * contains the original file may be tampered once the filtering is
+ * complete. Regardless, the `dest` buffer will always contain the final
+ * result of the filtering
*
* @param dest Buffer to store the result of the filtering
* @param source Buffer containing the document to filter
- * @param filters A non-empty vector of filters as supplied by `git_filters_load`
+ * @param filters Vector of filters as supplied by `git_filters_load`
* @return 0 on success, an error code otherwise
*/
extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters);
diff --git a/tests-clar/checkout/crlf.c b/tests-clar/checkout/crlf.c
index 285b1f272..5f5f1b776 100644
--- a/tests-clar/checkout/crlf.c
+++ b/tests-clar/checkout/crlf.c
@@ -1,19 +1,10 @@
#include "clar_libgit2.h"
#include "checkout_helpers.h"
+#include "../filter/crlf.h"
#include "git2/checkout.h"
#include "repository.h"
-#define UTF8_BOM "\xEF\xBB\xBF"
-#define ALL_CRLF_TEXT_RAW "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n"
-#define ALL_LF_TEXT_RAW "lf\nlf\nlf\nlf\nlf\n"
-#define MORE_CRLF_TEXT_RAW "crlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf\r\n"
-#define MORE_LF_TEXT_RAW "lf\nlf\ncrlf\r\nlf\nlf\n"
-
-#define ALL_LF_TEXT_AS_CRLF "lf\r\nlf\r\nlf\r\nlf\r\nlf\r\n"
-#define MORE_CRLF_TEXT_AS_CRLF "crlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf\r\n"
-#define MORE_LF_TEXT_AS_CRLF "lf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\n"
-
static git_repository *g_repo;
void test_checkout_crlf__initialize(void)
diff --git a/tests-clar/core/buffer.c b/tests-clar/core/buffer.c
index 8a0b6711f..11d173d49 100644
--- a/tests-clar/core/buffer.c
+++ b/tests-clar/core/buffer.c
@@ -919,6 +919,8 @@ void test_core_buffer__similarity_metric_whitespace(void)
git_buf_free(&buf);
}
+#include "../filter/crlf.h"
+
#define check_buf(expected,buf) do { \
cl_assert_equal_s(expected, buf.ptr); \
cl_assert_equal_sz(strlen(expected), buf.size); } while (0)
@@ -934,16 +936,16 @@ void test_core_buffer__lf_and_crlf_conversions(void)
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("lf\r\nlf\r\nlf\r\nlf\r\n", tgt);
- cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_crlf_to_lf(&tgt, &src));
- /* no conversion needed if all LFs already */
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(src.ptr, tgt);
git_buf_sets(&src, "\nlf\nlf\nlf\nlf\nlf");
cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
check_buf("\r\nlf\r\nlf\r\nlf\r\nlf\r\nlf", tgt);
- cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_crlf_to_lf(&tgt, &src));
- /* no conversion needed if all LFs already */
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(src.ptr, tgt);
/* CRLF source */
@@ -993,10 +995,45 @@ void test_core_buffer__lf_and_crlf_conversions(void)
check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt);
git_buf_sets(&src, "\rcr\r");
- cl_assert_equal_i(GIT_ENOTFOUND, git_buf_text_lf_to_crlf(&tgt, &src));
+ cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+ check_buf(src.ptr, tgt);
cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
check_buf("\rcr\r", tgt);
git_buf_free(&src);
git_buf_free(&tgt);
+
+ /* blob correspondence tests */
+
+ git_buf_sets(&src, ALL_CRLF_TEXT_RAW);
+ cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+ check_buf(ALL_CRLF_TEXT_AS_CRLF, tgt);
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(ALL_CRLF_TEXT_AS_LF, tgt);
+ git_buf_free(&src);
+ git_buf_free(&tgt);
+
+ git_buf_sets(&src, ALL_LF_TEXT_RAW);
+ cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+ check_buf(ALL_LF_TEXT_AS_CRLF, tgt);
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(ALL_LF_TEXT_AS_LF, tgt);
+ git_buf_free(&src);
+ git_buf_free(&tgt);
+
+ git_buf_sets(&src, MORE_CRLF_TEXT_RAW);
+ cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+ check_buf(MORE_CRLF_TEXT_AS_CRLF, tgt);
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(MORE_CRLF_TEXT_AS_LF, tgt);
+ git_buf_free(&src);
+ git_buf_free(&tgt);
+
+ git_buf_sets(&src, MORE_LF_TEXT_RAW);
+ cl_git_pass(git_buf_text_lf_to_crlf(&tgt, &src));
+ check_buf(MORE_LF_TEXT_AS_CRLF, tgt);
+ cl_git_pass(git_buf_text_crlf_to_lf(&tgt, &src));
+ check_buf(MORE_LF_TEXT_AS_LF, tgt);
+ git_buf_free(&src);
+ git_buf_free(&tgt);
}
diff --git a/tests-clar/filter/blob.c b/tests-clar/filter/blob.c
new file mode 100644
index 000000000..27e001f99
--- /dev/null
+++ b/tests-clar/filter/blob.c
@@ -0,0 +1,43 @@
+#include "clar_libgit2.h"
+#include "crlf.h"
+
+static git_repository *g_repo = NULL;
+
+void test_filter_blob__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("crlf");
+ cl_git_mkfile("crlf/.gitattributes",
+ "*.txt text\n*.bin binary\n*.crlf text eol=crlf\n*.lf text eol=lf\n");
+}
+
+void test_filter_blob__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_filter_blob__all_crlf(void)
+{
+ git_blob *blob;
+ git_buffer buf = GIT_BUFFER_INIT;
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "a9a2e891")); /* all-crlf */
+
+ cl_assert_equal_s(ALL_CRLF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filtered_content(&buf, blob, "file.bin", 1));
+
+ cl_assert_equal_s(ALL_CRLF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filtered_content(&buf, blob, "file.crlf", 1));
+
+ /* in this case, raw content has crlf in it already */
+ cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filtered_content(&buf, blob, "file.lf", 1));
+
+ cl_assert_equal_s(ALL_CRLF_TEXT_AS_LF, buf.ptr);
+
+ git_buffer_free(&buf);
+ git_blob_free(blob);
+}
diff --git a/tests-clar/filter/crlf.h b/tests-clar/filter/crlf.h
new file mode 100644
index 000000000..8fadee950
--- /dev/null
+++ b/tests-clar/filter/crlf.h
@@ -0,0 +1,26 @@
+#ifndef INCLUDE_filter_crlf_h__
+#define INCLUDE_filter_crlf_h__
+
+/*
+ * file content for files in the resources/crlf repository
+ */
+
+#define UTF8_BOM "\xEF\xBB\xBF"
+
+#define ALL_CRLF_TEXT_RAW "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n"
+#define ALL_LF_TEXT_RAW "lf\nlf\nlf\nlf\nlf\n"
+#define MORE_CRLF_TEXT_RAW "crlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf\r\n"
+#define MORE_LF_TEXT_RAW "lf\nlf\ncrlf\r\nlf\nlf\n"
+
+#define ALL_CRLF_TEXT_AS_CRLF ALL_CRLF_TEXT_RAW
+#define ALL_LF_TEXT_AS_CRLF "lf\r\nlf\r\nlf\r\nlf\r\nlf\r\n"
+#define MORE_CRLF_TEXT_AS_CRLF "crlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf\r\n"
+#define MORE_LF_TEXT_AS_CRLF "lf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\n"
+
+#define ALL_CRLF_TEXT_AS_LF "crlf\ncrlf\ncrlf\ncrlf\n"
+#define ALL_LF_TEXT_AS_LF ALL_LF_TEXT_RAW
+#define MORE_CRLF_TEXT_AS_LF "crlf\ncrlf\nlf\ncrlf\ncrlf\n"
+#define MORE_LF_TEXT_AS_LF "lf\nlf\ncrlf\nlf\nlf\n"
+
+
+#endif