Index: build.conf =================================================================== --- build.conf (revision 1050825) +++ build.conf (working copy) @@ -865,6 +865,14 @@ sources = target-test.c install = test libs = libsvn_test libsvn_subr apriconv apr +[subst_translate-test] +description = Test the svn_subst_translate* functions +type = exe +path = subversion/tests/libsvn_subr +sources = subst_translate-test.c +install = test +libs = libsvn_test libsvn_subr apriconv apr + [translate-test] description = Test eol conversion and keyword substitution routines type = exe Index: subversion/include/svn_subst.h =================================================================== --- subversion/include/svn_subst.h (revision 1050825) +++ subversion/include/svn_subst.h (working copy) @@ -592,19 +592,46 @@ svn_subst_stream_detranslated(svn_stream_t **strea /* EOL conversion and character encodings */ +/** Similar to svn_subst_translate_string2(), except that the information about + * whether re-encoding or line ending translation were performed is discarded. + * + * @deprecated Provided for backward compatibility with the 1.6 API. + */ +SVN_DEPRECATED +svn_error_t *svn_subst_translate_string(svn_string_t **new_value, + const svn_string_t *value, + const char *encoding, + apr_pool_t *pool); + /** Translate the string @a value from character encoding @a encoding to * UTF8, and also from its current line-ending style to LF line-endings. If * @a encoding is @c NULL, translate from the system-default encoding. * + * If @a translated_to_utf8 is not @c NULL, then set @a *translated_to_utf8 + * to @c TRUE if at least one character of @a value in the source character + * encoding was translated to UTF-8, or to @c FALSE otherwise. + * + * If @a translated_line_endings is not @c NULL, then set @a + * *translated_line_endings to @c TRUE if at least one line ending was + * changed to LF, or to @c FALSE otherwise. + * * Recognized line endings are LF, CR, CRLF. If @a value has inconsistent * line endings, return @c SVN_ERR_IO_INCONSISTENT_EOL. * - * Set @a *new_value to the translated string, allocated in @a pool. + * Set @a *new_value to the translated string, allocated in @a result_pool. + * + * @a scratch_pool is used for temporary allocations. + * + * @since New in 1.7. */ -svn_error_t *svn_subst_translate_string(svn_string_t **new_value, - const svn_string_t *value, - const char *encoding, - apr_pool_t *pool); +svn_error_t * +svn_subst_translate_string2(svn_string_t **new_value, + svn_boolean_t *translated_to_utf8, + svn_boolean_t *translated_line_endings, + const svn_string_t *value, + const char *encoding, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /** Translate the string @a value from UTF8 and LF line-endings into native * character encoding and native line-endings. If @a for_output is TRUE, Index: subversion/libsvn_subr/subst.c =================================================================== --- subversion/libsvn_subr/subst.c (revision 1050825) +++ subversion/libsvn_subr/subst.c (working copy) @@ -606,11 +606,34 @@ translate_keyword(char *buf, return FALSE; } +/* A boolean expression that evaluates to true if the first STR_LEN characters + of the string STR are one of the end-of-line strings LF, CR, or CRLF; + to false otherwise. */ +#define STRING_IS_EOL(str, str_len) \ + (((str_len) == 2 && (str)[0] == '\r' && (str)[1] == '\n') || \ + ((str_len) == 1 && ((str)[0] == '\n' || (str)[0] == '\r'))) +/* A boolean expression that evaluates to true if the end-of-line string EOL1, + having length EOL1_LEN, and the end-of-line string EOL2, having length + EOL2_LEN, are different, assuming that EOL1 and EOL2 are both from the + set {"\n", "\r", "\r\n"}; to false otherwise. + + Given that EOL1 and EOL2 are either "\n", "\r", or "\r\n", then if + EOL1_LEN is not the same as EOL2_LEN, then EOL1 and EOL2 are of course + different. If EOL1_LEN and EOL2_LEN are both 2 then EOL1 and EOL2 are both + "\r\n" and *EOL1 == *EOL2. Otherwise, EOL1_LEN and EOL2_LEN are both 1. + We need only check the one character for equality to determine whether + EOL1 and EOL2 are different in that case. */ +#define DIFFERENT_EOL_STRINGS(eol1, eol1_len, eol2, eol2_len) \ + (((eol1_len) != (eol2_len)) || (*(eol1) != *(eol2))) + + /* Translate the newline string NEWLINE_BUF (of length NEWLINE_LEN) to the newline string EOL_STR (of length EOL_STR_LEN), writing the result (which is always EOL_STR) to the stream DST. + This function assumes that NEWLINE_BUF is either "\n", "\r", or "\r\n". + Also check for consistency of the source newline strings across multiple calls, using SRC_FORMAT (length *SRC_FORMAT_LEN) as a cache of the first newline found. If the current newline is not the same @@ -620,6 +643,11 @@ translate_keyword(char *buf, newline in the file, and copy it to {SRC_FORMAT, *SRC_FORMAT_LEN} to use for later consistency checks. + If TRANSLATED_EOL is not NULL, then set *TRANSLATED_EOL to TRUE if the + newline string that was written (EOL_STR) is not the same as the newline + string that was translated (NEWLINE_BUF), otherwise leave *TRANSLATED_EOL + untouched. + Note: all parameters are required even if REPAIR is TRUE. ### We could require that REPAIR must not change across a sequence of calls, and could then optimize by not using SRC_FORMAT at all if @@ -633,17 +661,19 @@ translate_newline(const char *eol_str, const char *newline_buf, apr_size_t newline_len, svn_stream_t *dst, + svn_boolean_t *translated_eol, svn_boolean_t repair) { + SVN_ERR_ASSERT(STRING_IS_EOL(newline_buf, newline_len)); + /* If we've seen a newline before, compare it with our cache to check for consistency, else cache it for future comparisons. */ if (*src_format_len) { /* Comparing with cache. If we are inconsistent and we are NOT repairing the file, generate an error! */ - if ((! repair) && - ((*src_format_len != newline_len) || - (strncmp(src_format, newline_buf, newline_len)))) + if ((! repair) && DIFFERENT_EOL_STRINGS(src_format, *src_format_len, + newline_buf, newline_len)) return svn_error_create(SVN_ERR_IO_INCONSISTENT_EOL, NULL, NULL); } else @@ -653,8 +683,16 @@ translate_newline(const char *eol_str, strncpy(src_format, newline_buf, newline_len); *src_format_len = newline_len; } + /* Write the desired newline */ - return translate_write(dst, eol_str, eol_str_len); + SVN_ERR(translate_write(dst, eol_str, eol_str_len)); + + if (translated_eol != NULL && + (eol_str_len != newline_len || + memcmp(eol_str, newline_buf, eol_str_len) != 0)) + *translated_eol = TRUE; + + return SVN_NO_ERROR; } @@ -765,10 +803,12 @@ svn_subst_keywords_differ2(apr_hash_t *a, return FALSE; } + /* Baton for translate_chunk() to store its state in. */ struct translation_baton { const char *eol_str; + svn_boolean_t *translated_eol; svn_boolean_t repair; apr_hash_t *keywords; svn_boolean_t expand; @@ -813,6 +853,7 @@ struct translation_baton */ static struct translation_baton * create_translation_baton(const char *eol_str, + svn_boolean_t *translated_eol, svn_boolean_t repair, apr_hash_t *keywords, svn_boolean_t expand, @@ -826,6 +867,7 @@ create_translation_baton(const char *eol_str, b->eol_str = eol_str; b->eol_str_len = eol_str ? strlen(eol_str) : 0; + b->translated_eol = translated_eol; b->repair = repair; b->keywords = keywords; b->expand = expand; @@ -888,6 +930,9 @@ eol_unchanged(struct translation_baton *b, * To finish a series of chunk translations, flush all buffers by calling * this routine with a NULL value for BUF. * + * If B->translated_eol is not NULL, then set *B->translated_eol to TRUE if + * an end-of-line sequence was changed, otherwise leave it untouched. + * * Use POOL for temporary allocations. */ static svn_error_t * @@ -924,7 +969,8 @@ translate_chunk(svn_stream_t *dst, SVN_ERR(translate_newline(b->eol_str, b->eol_str_len, b->src_format, &b->src_format_len, b->newline_buf, - b->newline_off, dst, b->repair)); + b->newline_off, dst, b->translated_eol, + b->repair)); b->newline_off = 0; } @@ -1070,7 +1116,8 @@ translate_chunk(svn_stream_t *dst, b->src_format, &b->src_format_len, b->newline_buf, - b->newline_off, dst, b->repair)); + b->newline_off, dst, + b->translated_eol, b->repair)); b->newline_off = 0; break; @@ -1086,7 +1133,7 @@ translate_chunk(svn_stream_t *dst, SVN_ERR(translate_newline(b->eol_str, b->eol_str_len, b->src_format, &b->src_format_len, b->newline_buf, b->newline_off, - dst, b->repair)); + dst, b->translated_eol, b->repair)); b->newline_off = 0; } @@ -1349,14 +1396,20 @@ svn_subst_read_specialfile(svn_stream_t **stream, return SVN_NO_ERROR; } - -svn_stream_t * -svn_subst_stream_translated(svn_stream_t *stream, - const char *eol_str, - svn_boolean_t repair, - apr_hash_t *keywords, - svn_boolean_t expand, - apr_pool_t *result_pool) +/* Same as svn_subst_stream_translated(), except for the following. + * + * If TRANSLATED_EOL is not NULL, then reading and/or writing to the stream + * will set *TRANSLATED_EOL to TRUE if an end-of-line sequence was changed, + * otherwise leave it untouched. + */ +static svn_stream_t * +stream_translated(svn_stream_t *stream, + const char *eol_str, + svn_boolean_t *translated_eol, + svn_boolean_t repair, + apr_hash_t *keywords, + svn_boolean_t expand, + apr_pool_t *result_pool) { struct translated_stream_baton *baton = apr_palloc(result_pool, sizeof(*baton)); @@ -1398,9 +1451,11 @@ svn_subst_read_specialfile(svn_stream_t **stream, /* Setup the baton fields */ baton->stream = stream; baton->in_baton - = create_translation_baton(eol_str, repair, keywords, expand, result_pool); + = create_translation_baton(eol_str, translated_eol, repair, keywords, + expand, result_pool); baton->out_baton - = create_translation_baton(eol_str, repair, keywords, expand, result_pool); + = create_translation_baton(eol_str, translated_eol, repair, keywords, + expand, result_pool); baton->written = FALSE; baton->readbuf = svn_stringbuf_create("", result_pool); baton->readbuf_off = 0; @@ -1417,15 +1472,32 @@ svn_subst_read_specialfile(svn_stream_t **stream, return s; } +svn_stream_t * +svn_subst_stream_translated(svn_stream_t *stream, + const char *eol_str, + svn_boolean_t repair, + apr_hash_t *keywords, + svn_boolean_t expand, + apr_pool_t *result_pool) +{ + return stream_translated(stream, eol_str, NULL, repair, keywords, expand, + result_pool); +} -svn_error_t * -svn_subst_translate_cstring2(const char *src, - const char **dst, - const char *eol_str, - svn_boolean_t repair, - apr_hash_t *keywords, - svn_boolean_t expand, - apr_pool_t *pool) +/* Same as svn_subst_translate_cstring2(), except for the following. + * + * If TRANSLATED_EOL is not NULL, then set *TRANSLATED_EOL to TRUE if an + * end-of-line sequence was changed, or to FALSE otherwise. + */ +static svn_error_t * +translate_cstring(const char **dst, + svn_boolean_t *translated_eol, + const char *src, + const char *eol_str, + svn_boolean_t repair, + apr_hash_t *keywords, + svn_boolean_t expand, + apr_pool_t *pool) { svn_stringbuf_t *dst_stringbuf; svn_stream_t *dst_stream; @@ -1442,9 +1514,12 @@ svn_subst_read_specialfile(svn_stream_t **stream, dst_stringbuf = svn_stringbuf_create("", pool); dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool); + if (translated_eol) + *translated_eol = FALSE; + /* Another wrapper to translate the content. */ - dst_stream = svn_subst_stream_translated(dst_stream, eol_str, repair, - keywords, expand, pool); + dst_stream = stream_translated(dst_stream, eol_str, translated_eol, repair, + keywords, expand, pool); /* Jam the text into the destination stream (to translate it). */ SVN_ERR(svn_stream_write(dst_stream, src, &len)); @@ -1456,6 +1531,19 @@ svn_subst_read_specialfile(svn_stream_t **stream, return SVN_NO_ERROR; } +svn_error_t * +svn_subst_translate_cstring2(const char *src, + const char **dst, + const char *eol_str, + svn_boolean_t repair, + apr_hash_t *keywords, + svn_boolean_t expand, + apr_pool_t *pool) +{ + return translate_cstring(dst, NULL, src, eol_str, repair, keywords, expand, + pool); +} + /* Given a special file at SRC, generate a textual representation of it in a normal file at DST. Perform all allocations in POOL. */ /* ### this should be folded into svn_subst_copy_and_translate3 */ @@ -1768,14 +1856,16 @@ svn_subst_stream_from_specialfile(svn_stream_t **s /*** String translation */ svn_error_t * -svn_subst_translate_string(svn_string_t **new_value, - const svn_string_t *value, - const char *encoding, - apr_pool_t *pool) +svn_subst_translate_string2(svn_string_t **new_value, + svn_boolean_t *translated_to_utf8, + svn_boolean_t *translated_line_endings, + const svn_string_t *value, + const char *encoding, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { const char *val_utf8; const char *val_utf8_lf; - apr_pool_t *scratch_pool = svn_pool_create(pool); if (value == NULL) { @@ -1793,16 +1883,19 @@ svn_error_t * SVN_ERR(svn_utf_cstring_to_utf8(&val_utf8, value->data, scratch_pool)); } - SVN_ERR(svn_subst_translate_cstring2(val_utf8, - &val_utf8_lf, - "\n", /* translate to LF */ - FALSE, /* no repair */ - NULL, /* no keywords */ - FALSE, /* no expansion */ - scratch_pool)); + if (translated_to_utf8) + *translated_to_utf8 = (strcmp(value->data, val_utf8) != 0); - *new_value = svn_string_create(val_utf8_lf, pool); - svn_pool_destroy(scratch_pool); + SVN_ERR(translate_cstring(&val_utf8_lf, + translated_line_endings, + val_utf8, + "\n", /* translate to LF */ + FALSE, /* no repair */ + NULL, /* no keywords */ + FALSE, /* no expansion */ + scratch_pool)); + + *new_value = svn_string_create(val_utf8_lf, result_pool); return SVN_NO_ERROR; } Index: subversion/libsvn_subr/deprecated.c =================================================================== --- subversion/libsvn_subr/deprecated.c (revision 1050825) +++ subversion/libsvn_subr/deprecated.c (working copy) @@ -250,6 +250,16 @@ svn_subst_stream_translated_to_normal_form(svn_str } svn_error_t * +svn_subst_translate_string(svn_string_t **new_value, + const svn_string_t *value, + const char *encoding, + apr_pool_t *pool) +{ + return svn_subst_translate_string2(new_value, NULL, NULL, value, + encoding, pool, pool); +} + +svn_error_t * svn_subst_stream_detranslated(svn_stream_t **stream_p, const char *src, svn_subst_eol_style_t eol_style, Index: subversion/tests/libsvn_subr/subst_translate-test.c =================================================================== --- subversion/tests/libsvn_subr/subst_translate-test.c (revision 0) +++ subversion/tests/libsvn_subr/subst_translate-test.c (revision 0) @@ -0,0 +1,313 @@ +/* + * subst_translate-test.c -- test the svn_subst_translate* 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 +#include + +#include +#include +#include + +#include "../svn_test.h" + +#include "svn_types.h" +#include "svn_error_codes.h" +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_string.h" +#include "svn_subst.h" + +static char s_buf[2053]; + +/** + * Converts the string STR to C code for a string literal that represents it. + * + * Not thread safe. The returned pointer is to a static buffer, so it does + * not need to be freed. + */ +static char* +strtocsrc(const char *str) +{ + char *p = s_buf; + *p++ = '"'; + + size_t i; + for (i = 0; str[i] != '\0' && i < 512; ++i) { + sprintf(p, "\\x%02x", (int) str[i]); + p += 4; + } + + if (i < 512) { + *p++ = '"'; + } else { + *p++ = '.'; + *p++ = '.'; + *p++ = '.'; + // no terminating double quote character + } + + *p = '\0'; + + return s_buf; +} + +static svn_error_t * +test_svn_subst_translate_string2(apr_pool_t *pool) +{ + svn_string_t *new_value; + svn_boolean_t translated_to_utf8, translated_line_endings; + + /* No reencoding, no translation of line endings */ + const char data0[] = "abcdefz"; + svn_string_t *string0 = svn_string_create(data0, pool); + new_value = NULL; + translated_line_endings = TRUE; + SVN_ERR(svn_subst_translate_string2(&new_value, + NULL, &translated_line_endings, + string0, "UTF-8", pool, pool)); + if (strcmp(new_value->data, data0) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING0 should " + "yield \"abcdefz\"."); + if (translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING0 should " + "reset TRANSLATED_LINE_ENDINGS to FALSE because " + "the string does not contain a new line to " + "translate."); + new_value = NULL; + translated_to_utf8 = TRUE; + translated_line_endings = TRUE; + SVN_ERR(svn_subst_translate_string2(&new_value, &translated_to_utf8, + &translated_line_endings, + string0, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, data0) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING0 " + "should yield \"abcdefz\"."); + if (translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING0 should " + "reset TRANSLATED_TO_UTF8 to FALSE because " + "the string should not be changed as a result of " + "reencoding to UTF-8."); + if (translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING0 " + "should reset TRANSLATED_LINE_ENDINGS to FALSE " + "because the string does not contain a new line " + "to translate."); + + /* No reencoding, translation of line endings */ + const char data1[] = " \r\n\r\n \r\n \r\n"; + svn_string_t *string1 = svn_string_create(data1, pool); + const char expected_result1[] = " \n\n \n \n"; + new_value = NULL; + translated_line_endings = FALSE; + SVN_ERR(svn_subst_translate_string2(&new_value, + NULL, &translated_line_endings, + string1, "UTF-8", pool, pool)); + if (strcmp(new_value->data, expected_result1) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING1 should " + "yield \" \\n\\n \\n \\n\"."); + if (! translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING1 should " + "set TRANSLATED_LINE_ENDINGS to TRUE because the " + "string has Windows-style line endings that " + "were translated."); + new_value = NULL; + translated_to_utf8 = TRUE; + translated_line_endings = FALSE; + SVN_ERR(svn_subst_translate_string2(&new_value, &translated_to_utf8, + &translated_line_endings, + string1, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, expected_result1) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING1 " + "should yield \" \\n\\n \\n \\n\"" + "."); + if (translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING1 should " + "reset TRANSLATED_TO_UTF8 to FALSE because " + "the string should not be changed as a result of " + "reencoding to UTF-8."); + if (! translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING1 " + "should set TRANSLATED_LINE_ENDINGS to TRUE " + "because the string has Windows-style line " + "endings that were translated."); + + /* Reencoding, no translation of line endings */ + const char data2[] = "\xc7\xa9\xf4\xdf"; + svn_string_t *string2 = svn_string_create(data2, pool); + const char expected_result2[] = "\xc3\x87\xc2\xa9\xc3\xb4\xc3\x9f"; + new_value = NULL; + translated_to_utf8 = FALSE; + SVN_ERR(svn_subst_translate_string2(&new_value, + &translated_to_utf8, NULL, + string2, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, expected_result2) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING2 should " + "yield \"\\xc3\\x87\\xc2\\xa9\\xc3\\xb4\\xc3\\x9f" + "\". Instead, got %s.", + strtocsrc(new_value->data)); + if (! translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING2 should " + "set TRANSLATED_TO_UTF8 to TRUE."); + new_value = NULL; + translated_to_utf8 = FALSE; + translated_line_endings = TRUE; + SVN_ERR(svn_subst_translate_string2(&new_value, &translated_to_utf8, + &translated_line_endings, + string2, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, expected_result2) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING2 " + "should yield \"\\xc3\\x87\\xc2\\xa9\\xc3\\xb4" + "\\xc3\\x9f\". Instead, got %s.", + strtocsrc(new_value->data)); + if (! translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING2 " + "should set TRANSLATED_TO_UTF8 to TRUE."); + if (translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING2 should " + "reset TRANSLATED_LINE_ENDINGS to FALSE."); + + /* Reencoding, translation of line endings */ + const char data3[] = "\xc7\xa9\xf4\xdf\r\n"; + svn_string_t *string3 = svn_string_create(data3, pool); + const char expected_result3[] = "\xc3\x87\xc2\xa9\xc3\xb4\xc3\x9f\n"; + new_value = NULL; + translated_to_utf8 = FALSE; + SVN_ERR(svn_subst_translate_string2(&new_value, + &translated_to_utf8, NULL, + string3, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, expected_result3) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING3 should " + "yield \"\\xc3\\x87\\xc2\\xa9\\xc3\\xb4\\xc3\\x9f" + "\\x0a\". Instead, got %s.", + strtocsrc(new_value->data)); + if (! translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING3 should " + "set TRANSLATED_TO_UTF8 to TRUE."); + new_value = NULL; + translated_to_utf8 = FALSE; + translated_line_endings = FALSE; + SVN_ERR(svn_subst_translate_string2(&new_value, &translated_to_utf8, + &translated_line_endings, + string3, "ISO-8859-1", pool, pool)); + if (strcmp(new_value->data, expected_result3) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING3 " + "should yield \"\\xc3\\x87\\xc2\\xa9\\xc3\\xb4" + "\\xc3\\x9f\\x0a\". Instead, got %s.", + strtocsrc(new_value->data)); + if (! translated_to_utf8) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "(2) svn_subst_translate_string2() on STRING3 " + "should set TRANSLATED_TO_UTF8 to TRUE."); + if (! translated_line_endings) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_string2() on STRING3 should " + "set TRANSLATED_LINE_ENDINGS to TRUE."); + + return SVN_NO_ERROR; +} + +/*static svn_error_t * +test_svn_subst_copy_and_translate4(apr_pool_t *pool) +{ + return SVN_NO_ERROR; +} + +static svn_error_t * +test_svn_subst_stream_translated(apr_pool_t *pool) +{ + return SVN_NO_ERROR; +}*/ + +static svn_error_t * +test_svn_subst_translate_cstring2(apr_pool_t *pool) +{ + /* Test the unusual case where EOL_STR is an empty string. */ + const char src0[] = " \r \n\r\n \n\n\n"; + const char *dest0 = NULL; + const char expected_result0[] = " "; + SVN_ERR(svn_subst_translate_cstring2(src0, &dest0, "", TRUE, NULL, FALSE, + pool)); + if (strcmp(dest0, expected_result0) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_cstring2() on SRC0 should " + "yield \" \"."); + + /* Test the unusual case where EOL_STR is not a standard EOL string. */ + const char src1[] = " \r \n\r\n \n\n\n"; + const char *dest1 = NULL; + const char expected_result1[] = " z zz zzz"; + SVN_ERR(svn_subst_translate_cstring2(src1, &dest1, "z", TRUE, NULL, FALSE, + pool)); + if (strcmp(dest1, expected_result1) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_cstring2() on SRC1 should " + "yield \" z zz zzz\"."); + const char src2[] = " \n \n "; + const char *dest2 = NULL; + const char expected_result2[] = " buzz buzz "; + SVN_ERR(svn_subst_translate_cstring2(src2, &dest2, "buzz", FALSE, NULL, FALSE, + pool)); + if (strcmp(dest2, expected_result2) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_cstring2() on SRC2 should " + "yield \" buzz buzz \"."); + const char src3[] = " \r\n \n"; + const char *dest3 = NULL; + const char expected_result3[] = " buzz buzz"; + SVN_ERR(svn_subst_translate_cstring2(src3, &dest3, "buzz", TRUE, NULL, FALSE, + pool)); + if (strcmp(dest3, expected_result3) != 0) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "svn_subst_translate_cstring2() on SRC3 should " + "yield \" buzz buzz\"."); + + return SVN_NO_ERROR; +} + +struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_svn_subst_translate_string2, + "test svn_subst_translate_string2()"), + SVN_TEST_PASS2(test_svn_subst_translate_cstring2, + "test svn_subst_translate_cstring2()"), + SVN_TEST_NULL + }; Property changes on: subversion/tests/libsvn_subr/subst_translate-test.c ___________________________________________________________________ Added: svn:eol-style + native