Hi,
As an addition to the merge_trivial optimizations, I added test cases for the
new file comparison functions, and also included test cases for the old
comparison functions which were not yet covered.
This way I also discovered a bug in the comparison functions, which is fixed in
this version of the patch.
[[[
Optimize merge_file_trivial() by avoiding to read the files twice by using a
new comparison function which compares 3 files at once. Also add
C tests for the new and existing file comparison functions in libsvn_subr/io.c
* subversion/include/svn_io.h
(svn_io_filesizes_three_different_p): Add new declaration
(svn_io_files_contents_three_same_p): Add new declaration
* subversion/libsvn_subr/io.c
(svn_io_filesizes_three_different_p): Add new function in analogy to
svn_io_filesizes_different_p().
(contents_three_identical_p): Add new function in analogy to
contents_identical_p().
(svn_io_files_contents_three_same_p): Add new function in analogy to
svn_io_files_contents_same_p.
* subversion/libsvn_wc/merge.c
(merge_file_trivial): Use the new three-file comparison functions to avoid
reading files twice.
* build.conf
Add the new io-test.c file to the build configuration.
* subversion/tests
add the temporary test file folder to svn:ignore.
* subversion/tests/libsvn_subr/io-test.c
(create_test_file): Helper function to create a test data file.
(create_comparison_candidates): Helper function to create the full set of
test data files.
(test_two_file_size_comparison): Test function for
svn_io_filesizes_different_p.
(test_two_file_content_comparison): Test function for
svn_io_files_contents_same_p.
(test_three_file_size_comparison): Test function for
test_three_file_size_comparison.
(test_three_file_content_comparison): Test function for
svn_io_files_contents_three_same_p.
Patch by: Markus Schaber <[email protected]>
]]]
Best regards
Markus Schaber
--
We software Automation.
3S-Smart Software Solutions GmbH
Markus Schaber | Developer
Memminger Str. 151 | 87439 Kempten | Germany | Tel. +49-831-54031-0 | Fax
+49-831-54031-50
Email: [email protected] | Web: http://www.3s-software.com
CoDeSys internet forum: http://forum.3s-software.com
Download CoDeSys sample projects:
http://www.3s-software.com/index.shtml?sample_projects
Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade
register: Kempten HRB 6186 | Tax ID No.: DE 167014915
Index: build.conf
===================================================================
--- build.conf (revision 1349693)
+++ build.conf (working copy)
@@ -757,6 +757,14 @@
install = test
libs = libsvn_test libsvn_subr apriconv apr
+[io-test]
+description = Test I/O Operations
+type = exe
+path = subversion/tests/libsvn_subr
+sources = io-test.c
+install = test
+libs = libsvn_test libsvn_subr apriconv apr
+
[opt-test]
description = Test options library
type = exe
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 1349990)
+++ subversion/include/svn_io.h (working copy)
@@ -607,6 +607,25 @@
const char *file2,
apr_pool_t *pool);
+/** Set @a *different_p12 to non-zero if @a file1 and @a file2 have different
+ * sizes, else set to zero. Do the similar for @a *different_p23 with
+ * @a file2 and @a file3, and @a *different_p13 for @a file1 and @a file3.
+ * All three of @a file1, @a file2 and @a file3 are utf8-encoded.
+ *
+ * Setting @a *different_p12 to zero does not mean the files definitely
+ * have the same size, it merely means that the sizes are not
+ * definitely different. That is, if the size of one or both files
+ * cannot be determined, then the sizes are not known to be different,
+ * so @a *different_p12 is set to 0.
+ */
+svn_error_t *
+svn_io_filesizes_three_different_p(svn_boolean_t *different_p12,
+ svn_boolean_t *different_p23,
+ svn_boolean_t *different_p13,
+ const char *file1,
+ const char *file2,
+ const char *file3,
+ apr_pool_t *pool);
/** Return in @a *checksum the checksum of type @a kind of @a file
* Use @a pool for temporary allocations and to allocate @a *checksum.
@@ -642,6 +661,20 @@
const char *file2,
apr_pool_t *pool);
+/** Set @a *same12 to TRUE if @a file1 and @a file2 have the same
+ * contents, else set it to FALSE. Do the similar for @a *same23
+ * with @a file2 and @a file3, and @a *same13 for @a file1 and @a
+ * file3. Use @a pool for temporary allocations.
+ */
+svn_error_t *
+svn_io_files_contents_three_same_p(svn_boolean_t *same12,
+ svn_boolean_t *same23,
+ svn_boolean_t *same13,
+ const char *file1,
+ const char *file2,
+ const char *file3,
+ apr_pool_t *pool);
+
/** Create file at utf8-encoded @a file with contents @a contents.
* @a file must not already exist.
* Use @a pool for memory allocations.
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 1349990)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -1311,6 +1311,43 @@
svn_error_t *
+svn_io_filesizes_three_different_p(svn_boolean_t *different_p12,
+ svn_boolean_t *different_p23,
+ svn_boolean_t *different_p13,
+ const char *file1,
+ const char *file2,
+ const char *file3,
+ apr_pool_t *pool)
+{
+ apr_finfo_t finfo1, finfo2, finfo3;
+ apr_status_t status1, status2, status3;
+ const char *file1_apr, *file2_apr, *file3_apr;
+
+ /* Not using svn_io_stat() because don't want to generate
+ svn_error_t objects for non-error conditions. */
+
+ SVN_ERR(cstring_from_utf8(&file1_apr, file1, pool));
+ SVN_ERR(cstring_from_utf8(&file2_apr, file2, pool));
+ SVN_ERR(cstring_from_utf8(&file3_apr, file3, pool));
+
+ /* Stat all three files */
+ status1 = apr_stat(&finfo1, file1_apr, APR_FINFO_MIN, pool);
+ status2 = apr_stat(&finfo2, file2_apr, APR_FINFO_MIN, pool);
+ status3 = apr_stat(&finfo3, file3_apr, APR_FINFO_MIN, pool);
+
+ /* If we got an error stat'ing a file, it could be because the
+ file was removed... or who knows. Whatever the case, we
+ don't know if the filesizes are definitely different, so
+ assume that they're not. */
+ *different_p12 = !status1 && !status2 && finfo1.size != finfo2.size;
+ *different_p23 = !status2 && !status3 && finfo2.size != finfo3.size;
+ *different_p13 = !status1 && !status3 && finfo1.size != finfo3.size;
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
svn_io_file_checksum2(svn_checksum_t **checksum,
const char *file,
svn_checksum_kind_t kind,
@@ -4072,6 +4109,136 @@
+/* Do a byte-for-byte comparison of FILE1, FILE2 and FILE3. */
+static svn_error_t *
+contents_three_identical_p(svn_boolean_t *identical_p12,
+ svn_boolean_t *identical_p23,
+ svn_boolean_t *identical_p13,
+ const char *file1,
+ const char *file2,
+ const char *file3,
+ apr_pool_t *pool)
+{
+ svn_error_t *err;
+ apr_size_t bytes_read1, bytes_read2, bytes_read3;
+ char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
+ char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
+ char *buf3 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
+ apr_file_t *file1_h;
+ apr_file_t *file2_h;
+ apr_file_t *file3_h;
+ svn_boolean_t eof1 = FALSE;
+ svn_boolean_t eof2 = FALSE;
+ svn_boolean_t eof3 = FALSE;
+ svn_boolean_t read_1, read_2, read_3;
+
+ SVN_ERR(svn_io_file_open(&file1_h, file1, APR_READ, APR_OS_DEFAULT,
+ pool));
+
+ err = svn_io_file_open(&file2_h, file2, APR_READ, APR_OS_DEFAULT,
+ pool);
+
+ if (err)
+ return svn_error_trace(
+ svn_error_compose_create(err,
+ svn_io_file_close(file1_h, pool)));
+
+ err = svn_io_file_open(&file3_h, file3, APR_READ, APR_OS_DEFAULT,
+ pool);
+
+ if (err)
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_error_compose_create(svn_io_file_close(file1_h, pool),
+ svn_io_file_close(file2_h,
pool))));
+
+ /* assume TRUE, until disproved below */
+ *identical_p12 = *identical_p23 = *identical_p13 = TRUE;
+ /* We need to read as long as no error occurs, and as long as one of the
+ * flags could still change due to a read operation */
+ while (!err
+ && (*identical_p12 && !eof1 && !eof2)
+ || (*identical_p23 && !eof2 && !eof3)
+ || (*identical_p13 && !eof1 && !eof3))
+ {
+ read_1 = read_2 = read_3 = FALSE;
+
+ /* As long as a file is not at the end yet, and it is still
+ * potentially identical to another file, we read the next chunk.*/
+ if (!eof1 && (identical_p12 || identical_p13))
+ {
+ err = svn_io_file_read_full2(file1_h, buf1,
+ SVN__STREAM_CHUNK_SIZE, &bytes_read1,
+ &eof1, pool);
+ if (err)
+ break;
+ read_1 = TRUE;
+ }
+
+ if (!eof2 && (identical_p12 || identical_p23))
+ {
+ err = svn_io_file_read_full2(file2_h, buf2,
+ SVN__STREAM_CHUNK_SIZE, &bytes_read2,
+ &eof2, pool);
+ if (err)
+ break;
+ read_2 = TRUE;
+ }
+
+ if (!eof3 && (identical_p13 || identical_p23))
+ {
+ err = svn_io_file_read_full2(file3_h, buf3,
+ SVN__STREAM_CHUNK_SIZE, &bytes_read3,
+ &eof3, pool);
+ if (err)
+ break;
+ read_3 = TRUE;
+ }
+
+ /* If the files are still marked identical, and at least one of them
+ * is not at the end of file, we check whether they differ, and set
+ * their flag to false then. */
+ if (*identical_p12
+ && (read_1 || read_2)
+ && ((eof1 != eof2)
+ || (bytes_read1 != bytes_read2)
+ || memcmp(buf1, buf2, bytes_read1)))
+ {
+ *identical_p12 = FALSE;
+ }
+
+ if (*identical_p23
+ && (read_2 || read_3)
+ && ((eof2 != eof3)
+ || (bytes_read2 != bytes_read3)
+ || memcmp(buf2, buf3, bytes_read2)))
+ {
+ *identical_p23 = FALSE;
+ }
+
+ if (*identical_p13
+ && (read_1 || read_3)
+ && ((eof1 != eof3)
+ || (bytes_read1 != bytes_read3)
+ || memcmp(buf1, buf3, bytes_read3)))
+ {
+ *identical_p13 = FALSE;
+ }
+ }
+
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_error_compose_create(
+ svn_io_file_close(file1_h, pool),
+ svn_error_compose_create(
+ svn_io_file_close(file2_h, pool),
+ svn_io_file_close(file3_h, pool)))));
+}
+
+
+
svn_error_t *
svn_io_files_contents_same_p(svn_boolean_t *same,
const char *file1,
@@ -4098,6 +4265,53 @@
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_io_files_contents_three_same_p(svn_boolean_t *same12,
+ svn_boolean_t *same23,
+ svn_boolean_t *same13,
+ const char *file1,
+ const char *file2,
+ const char *file3,
+ apr_pool_t *pool)
+{
+ svn_boolean_t diff_size12, diff_size23, diff_size13;
+
+ SVN_ERR(svn_io_filesizes_three_different_p(&diff_size12,
+ &diff_size23,
+ &diff_size13,
+ file1,
+ file2,
+ file3,
+ pool));
+
+ if (diff_size12 && diff_size23 && diff_size13)
+ {
+ *same12 = *same23 = *same13 = FALSE;
+ }
+ else if (diff_size12 && diff_size23)
+ {
+ *same12 = *same23 = FALSE;
+ SVN_ERR(contents_identical_p(same13, file1, file3, pool));
+ }
+ else if (diff_size23 && diff_size13)
+ {
+ *same23 = *same13 = FALSE;
+ SVN_ERR(contents_identical_p(same12, file1, file2, pool));
+ }
+ else if (diff_size12 && diff_size13)
+ {
+ *same12 = *same13 = FALSE;
+ SVN_ERR(contents_identical_p(same23, file2, file3, pool));
+ }
+ else
+ {
+ SVN_ERR_ASSERT(!diff_size12 && !diff_size23 && !diff_size13);
+ SVN_ERR(contents_three_identical_p(same12, same23, same13, file1, file2,
file3, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
#ifdef WIN32
/* Counter value of file_mktemp request (used in a threadsafe way), to make
sure that a single process normally never generates the same tempname
Index: subversion/libsvn_wc/merge.c
===================================================================
--- subversion/libsvn_wc/merge.c (revision 1349990)
+++ subversion/libsvn_wc/merge.c (working copy)
@@ -948,7 +948,9 @@
apr_pool_t *scratch_pool)
{
svn_skel_t *work_item;
- svn_boolean_t same_contents = FALSE;
+ svn_boolean_t same_left_right;
+ svn_boolean_t same_right_target;
+ svn_boolean_t same_left_target;
svn_node_kind_t kind;
svn_boolean_t is_special;
@@ -961,19 +963,23 @@
return SVN_NO_ERROR;
}
+ /* Check the files */
+ SVN_ERR(svn_io_files_contents_three_same_p(&same_left_right,
+ &same_right_target,
+ &same_left_target,
+ left_abspath,
+ right_abspath,
+ detranslated_target_abspath,
+ scratch_pool));
+
/* If the LEFT side of the merge is equal to WORKING, then we can
* copy RIGHT directly. */
- SVN_ERR(svn_io_files_contents_same_p(&same_contents, left_abspath,
- detranslated_target_abspath,
- scratch_pool));
- if (same_contents)
+ if (same_left_target)
{
/* Check whether the left side equals the right side.
* If it does, there is no change to merge so we leave the target
* unchanged. */
- SVN_ERR(svn_io_files_contents_same_p(&same_contents, left_abspath,
- right_abspath, scratch_pool));
- if (same_contents)
+ if (same_left_right)
{
*merge_outcome = svn_wc_merge_unchanged;
}
@@ -1002,10 +1008,7 @@
* conflicted them needlessly, while merge_text_file figured it out
* eventually and returned svn_wc_merge_unchanged for them, which
* is what we do here. */
- SVN_ERR(svn_io_files_contents_same_p(&same_contents,
- detranslated_target_abspath,
- right_abspath, scratch_pool));
- if (same_contents)
+ if (same_right_target)
{
*merge_outcome = svn_wc_merge_unchanged;
return SVN_NO_ERROR;
Index: subversion/tests
===================================================================
--- subversion/tests (revision 1349693)
+++ subversion/tests (working copy)
Property changes on: subversion/tests
___________________________________________________________________
Modified: svn:ignore
## -7,3 +7,4 ##
*~
.*~
svnserveautocheck.pid
+svn-test-work
Index: subversion/tests/libsvn_subr/io-test.c
===================================================================
--- subversion/tests/libsvn_subr/io-test.c (revision 0)
+++ subversion/tests/libsvn_subr/io-test.c (working copy)
@@ -0,0 +1,429 @@
+/* io-test.c --- tests for some i/o functions
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <apr.h>
+
+#include "svn_pools.h"
+#include "svn_string.h"
+#include "private/svn_skel.h"
+
+#include "../svn_test.h"
+#include "../svn_test_fs.h"
+
+
+/* Helpers to create the test data directory. */
+
+#define TEST_DIR "io-test-temp"
+
+/* The definition for the test data files. */
+struct test_file_definition_t
+ {
+ /* The name of the test data file. */
+ const char* const name;
+
+ /* The string needs to contain up to 5 bytes, they
+ * are interpreded as:
+ * - first byte
+ * - filler between first and medium byte
+ * - medium byte (the byte in the middle of the file)
+ * - filler between medium and last byte
+ * - last byte.
+ * If the string is shorter than the file length,
+ * the test will fail. */
+ const char* const data;
+
+ /* The size of the file actually to create. */
+ const apr_off_t size;
+
+ /* The created path of the file. Will be filled in
+ * by create_test_file() */
+ char* created_path;
+ };
+
+struct test_file_definition_t test_file_definitions[] =
+ {
+ {"empty", "", 0},
+ {"single_a", "a", 1},
+ {"single_b", "b", 1},
+ {"hundred_a", "aaaaa", 100},
+ {"hundred_b", "bbbbb", 100},
+ {"hundred_b1", "baaaa", 100},
+ {"hundred_b2", "abaaa", 100},
+ {"hundred_b3", "aabaa", 100},
+ {"hundred_b4", "aaaba", 100},
+ {"hundred_b5", "aaaab", 100},
+ {"chunk_minus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_minus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_minus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_minus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_minus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_minus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE - 1},
+ {"chunk_a", "aaaaa", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_b1", "baaaa", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_b2", "abaaa", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_b3", "aabaa", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_b4", "aaaba", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_b5", "aaaab", SVN__STREAM_CHUNK_SIZE},
+ {"chunk_plus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE + 1},
+ {"chunk_plus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE + 1},
+ {"chunk_plus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE + 1},
+ {"chunk_plus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE + 1},
+ {"chunk_plus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE + 1},
+ {"chunk_plus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE + 1},
+ {"twochunk_minus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_minus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_minus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_minus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_minus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_minus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2 - 1},
+ {"twochunk_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2},
+ {"twochunk_plus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {"twochunk_plus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {"twochunk_plus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {"twochunk_plus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {"twochunk_plus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {"twochunk_plus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2 + 1},
+ {0},
+ };
+
+/* Function to prepare a single test file */
+
+static svn_error_t *
+create_test_file(struct test_file_definition_t* definition, apr_pool_t *pool,
apr_pool_t *scratch_pool)
+{
+ apr_status_t status;
+ apr_file_t *file_h;
+ apr_off_t midpos = definition->size / 2;
+ svn_error_t *err = NULL;
+ int i;
+
+ if (definition->size < 5)
+ SVN_ERR_ASSERT(strlen(definition->data) >= definition->size);
+ else
+ SVN_ERR_ASSERT(strlen(definition->data) >= 5);
+
+ status = apr_filepath_merge(&definition->created_path,
+ TEST_DIR,
+ definition->name,
+ 0,
+ pool);
+
+ if (status)
+ return svn_error_wrap_apr(status, "Can't merge filename '%s'",
+ definition->name);
+
+ SVN_ERR(svn_io_file_open(&file_h,
+ definition->created_path,
+ APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
+ APR_REG,
+ scratch_pool));
+
+ for (i=1; i <= definition->size; i += 1)
+ {
+ char c;
+ if (i == 1)
+ c = definition->data[0];
+ else if (i < midpos)
+ c = definition->data[1];
+ else if (i == midpos)
+ c = definition->data[2];
+ else if (i < definition->size)
+ c = definition->data[3];
+ else
+ c = definition->data[4];
+
+ status = apr_file_putc(c, file_h);
+
+ if (status)
+ break;
+ }
+
+ if (status)
+ err = svn_error_wrap_apr(status, "Can't merge filename '%s'",
+ definition->name);
+
+ return svn_error_compose_create(err, svn_io_file_close(file_h,
scratch_pool));
+}
+
+/* Function to prepare the whole set of on-disk files to be compared. */
+static svn_error_t *
+create_comparison_candidates(apr_pool_t *pool)
+{
+ apr_finfo_t finfo;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ struct test_file_definition_t *candidate;
+
+ /* If there's already a directory named io-test-temp, delete it.
+ Doing things this way means that repositories stick around after
+ a failure for postmortem analysis, but also that tests can be
+ re-run without cleaning out the repositories created by prior
+ runs. */
+ if (apr_stat(&finfo, TEST_DIR, APR_FINFO_TYPE, pool) == APR_SUCCESS)
+ {
+ if (finfo.filetype == APR_DIR)
+ SVN_ERR(svn_io_remove_dir2(TEST_DIR, TRUE, NULL, NULL, pool));
+ else
+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "there is already a file named '%s'",
TEST_DIR);
+ }
+
+ SVN_ERR(svn_io_dir_make(TEST_DIR, APR_OS_DEFAULT, pool));
+
+
+ for (candidate = test_file_definitions; candidate->name != NULL; candidate
+= 1)
+ {
+ svn_pool_clear(iterpool);
+ SVN_ERR(create_test_file(candidate, pool, iterpool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Functions to check the 2-way and 3-way file comparison functions. */
+
+/* Test 2-way file size checking */
+static svn_error_t *
+test_two_file_size_comparison(apr_pool_t *pool)
+{
+ struct test_file_definition_t *inner, *outer;
+ svn_boolean_t actual;
+ svn_boolean_t expected;
+ svn_error_t *err = SVN_NO_ERROR;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ SVN_ERR(create_comparison_candidates(pool));
+
+ for (outer = test_file_definitions; outer->name != NULL; outer += 1)
+ {
+ for (inner = test_file_definitions; inner->name != NULL; inner += 1)
+ {
+ svn_pool_clear(iterpool);
+
+ expected = inner->size != outer->size;
+
+ SVN_ERR(svn_io_filesizes_different_p(&actual,
+ inner->created_path,
+ outer->created_path,
+ iterpool));
+
+ if (expected != actual)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and '%s'",
+ inner->created_path,
+ outer->created_path));
+ }
+ }
+
+ return err;
+}
+
+
+/* Test 2-way file content checking */
+static svn_error_t *
+test_two_file_content_comparison(apr_pool_t *pool)
+{
+ struct test_file_definition_t *inner, *outer;
+ svn_boolean_t actual;
+ svn_boolean_t expected;
+ svn_error_t *err = SVN_NO_ERROR;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ SVN_ERR(create_comparison_candidates(pool));
+
+ for (outer = test_file_definitions; outer->name != NULL; outer += 1)
+ {
+ for (inner = test_file_definitions; inner->name != NULL; inner += 1)
+ {
+ svn_pool_clear(iterpool);
+
+ expected = inner->size == outer->size
+ && strcmp(inner->data, outer->data) == 0;
+
+ SVN_ERR(svn_io_files_contents_same_p(&actual,
+ inner->created_path,
+ outer->created_path,
+ iterpool));
+
+ if (expected != actual)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "content comparison problem: '%s' and '%s'",
+ inner->created_path,
+ outer->created_path));
+ }
+ }
+
+ return err;
+}
+
+
+/* Test 3-way file size checking */
+static svn_error_t *
+test_three_file_size_comparison(apr_pool_t *pool)
+{
+ struct test_file_definition_t *inner, *middle, *outer;
+ svn_boolean_t actual12, actual23, actual13;
+ svn_boolean_t expected12, expected23, expected13;
+ svn_error_t *err = SVN_NO_ERROR;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ SVN_ERR(create_comparison_candidates(pool));
+
+ for (outer = test_file_definitions; outer->name != NULL; outer += 1)
+ {
+ for (middle = test_file_definitions; middle->name != NULL; middle += 1)
+ {
+ for (inner = test_file_definitions; inner->name != NULL; inner += 1)
+ {
+ svn_pool_clear(iterpool);
+
+ expected12 = inner->size != middle->size;
+ expected23 = middle->size != outer->size;
+ expected13 = inner->size != outer->size;
+
+ SVN_ERR(svn_io_filesizes_three_different_p(&actual12,
+ &actual23,
+ &actual13,
+ inner->created_path,
+ middle->created_path,
+ outer->created_path,
+ iterpool));
+
+ if (expected12 != actual12)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ inner->created_path,
+ middle->created_path));
+
+ if (expected23 != actual23)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ middle->created_path,
+ outer->created_path));
+
+ if (expected13 != actual13)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ inner->created_path,
+ outer->created_path));
+ }
+ }
+ }
+
+ return err;
+}
+
+
+/* Test 3-way file content checking */
+static svn_error_t *
+test_three_file_content_comparison(apr_pool_t *pool)
+{
+ struct test_file_definition_t *inner, *middle, *outer;
+ svn_boolean_t actual12, actual23, actual13;
+ svn_boolean_t expected12, expected23, expected13;
+ svn_error_t *err = SVN_NO_ERROR;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ SVN_ERR(create_comparison_candidates(pool));
+
+ for (outer = test_file_definitions; outer->name != NULL; outer += 1)
+ {
+ for (middle = test_file_definitions; middle->name != NULL; middle += 1)
+ {
+ for (inner = test_file_definitions; inner->name != NULL; inner += 1)
+ {
+ svn_pool_clear(iterpool);
+
+ expected12 = outer->size == middle->size
+ && strcmp(outer->data, middle->data) == 0;
+ expected23 = middle->size == inner->size
+ && strcmp(middle->data, inner->data) == 0;
+ expected13 = outer->size == inner->size
+ && strcmp(outer->data, inner->data) == 0;
+
+ SVN_ERR(svn_io_files_contents_three_same_p(&actual12,
+ &actual23,
+ &actual13,
+ outer->created_path,
+ middle->created_path,
+ inner->created_path,
+ iterpool));
+
+ if (expected12 != actual12)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ inner->created_path,
+ middle->created_path));
+
+ if (expected23 != actual23)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ middle->created_path,
+ outer->created_path));
+
+ if (expected13 != actual13)
+ err = svn_error_compose_create(err,
+ svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "size comparison problem: '%s' and
'%s'",
+ inner->created_path,
+ outer->created_path));
+ }
+ }
+ }
+
+ return err;
+}
+
+
+
+/* The test table. */
+
+struct svn_test_descriptor_t test_funcs[] =
+ {
+ SVN_TEST_NULL,
+ SVN_TEST_PASS2(test_two_file_size_comparison,
+ "two file size comparison"),
+ SVN_TEST_PASS2(test_two_file_content_comparison,
+ "two file content comparison"),
+ SVN_TEST_PASS2(test_three_file_size_comparison,
+ "three file size comparison"),
+ SVN_TEST_PASS2(test_three_file_content_comparison,
+ "three file content comparison"),
+ SVN_TEST_NULL
+ };
Index: subversion/tests/libsvn_subr/io-test.c
===================================================================
--- subversion/tests/libsvn_subr/io-test.c (revision 0)
+++ subversion/tests/libsvn_subr/io-test.c (working copy)
Property changes on: subversion/tests/libsvn_subr/io-test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property