| /* |
| * stream-test.c -- test the stream 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 <stdio.h> |
| #include "svn_pools.h" |
| #include "svn_io.h" |
| #include "svn_subst.h" |
| #include "svn_base64.h" |
| #include <apr_general.h> |
| |
| #include "private/svn_io_private.h" |
| |
| #include "../svn_test.h" |
| |
| /*------------------------ Tests --------------------------- */ |
| |
| static svn_error_t * |
| test_stream_from_string(apr_pool_t *pool) |
| { |
| int i; |
| apr_pool_t *subpool = svn_pool_create(pool); |
| |
| #define NUM_TEST_STRINGS 4 |
| #define TEST_BUF_SIZE 10 |
| |
| static const char * const strings[NUM_TEST_STRINGS] = { |
| /* 0 */ |
| "", |
| /* 1 */ |
| "This is a string.", |
| /* 2 */ |
| "This is, by comparison to the previous string, a much longer string.", |
| /* 3 */ |
| "And if you thought that last string was long, you just wait until " |
| "I'm finished here. I mean, how can a string really claim to be long " |
| "when it fits on a single line of 80-columns? Give me a break. " |
| "Now, I'm not saying that I'm the longest string out there--far from " |
| "it--but I feel that it is safe to assume that I'm far longer than my " |
| "peers. And that demands some amount of respect, wouldn't you say?" |
| }; |
| |
| /* Test svn_stream_from_stringbuf() as a readable stream. */ |
| for (i = 0; i < NUM_TEST_STRINGS; i++) |
| { |
| svn_stream_t *stream; |
| char buffer[TEST_BUF_SIZE]; |
| svn_stringbuf_t *inbuf, *outbuf; |
| apr_size_t len; |
| |
| inbuf = svn_stringbuf_create(strings[i], subpool); |
| outbuf = svn_stringbuf_create_empty(subpool); |
| stream = svn_stream_from_stringbuf(inbuf, subpool); |
| len = TEST_BUF_SIZE; |
| while (len == TEST_BUF_SIZE) |
| { |
| /* Read a chunk ... */ |
| SVN_ERR(svn_stream_read_full(stream, buffer, &len)); |
| |
| /* ... and append the chunk to the stringbuf. */ |
| svn_stringbuf_appendbytes(outbuf, buffer, len); |
| } |
| |
| if (! svn_stringbuf_compare(inbuf, outbuf)) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Got unexpected result."); |
| |
| svn_pool_clear(subpool); |
| } |
| |
| /* Test svn_stream_from_stringbuf() as a writable stream. */ |
| for (i = 0; i < NUM_TEST_STRINGS; i++) |
| { |
| svn_stream_t *stream; |
| svn_stringbuf_t *inbuf, *outbuf; |
| apr_size_t amt_read, len; |
| |
| inbuf = svn_stringbuf_create(strings[i], subpool); |
| outbuf = svn_stringbuf_create_empty(subpool); |
| stream = svn_stream_from_stringbuf(outbuf, subpool); |
| amt_read = 0; |
| while (amt_read < inbuf->len) |
| { |
| /* Write a chunk ... */ |
| len = TEST_BUF_SIZE < (inbuf->len - amt_read) |
| ? TEST_BUF_SIZE |
| : inbuf->len - amt_read; |
| SVN_ERR(svn_stream_write(stream, inbuf->data + amt_read, &len)); |
| amt_read += len; |
| } |
| |
| if (! svn_stringbuf_compare(inbuf, outbuf)) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Got unexpected result."); |
| |
| svn_pool_clear(subpool); |
| } |
| |
| #undef NUM_TEST_STRINGS |
| #undef TEST_BUF_SIZE |
| |
| svn_pool_destroy(subpool); |
| return SVN_NO_ERROR; |
| } |
| |
| /* generate some poorly compressable data */ |
| static svn_stringbuf_t * |
| generate_test_bytes(int num_bytes, apr_pool_t *pool) |
| { |
| svn_stringbuf_t *buffer = svn_stringbuf_create_empty(pool); |
| int total, repeat, repeat_iter; |
| char c; |
| |
| for (total = 0, repeat = repeat_iter = 1, c = 0; total < num_bytes; total++) |
| { |
| svn_stringbuf_appendbyte(buffer, c); |
| |
| repeat_iter--; |
| if (repeat_iter == 0) |
| { |
| if (c == 127) |
| repeat++; |
| c = (char)((c + 1) % 127); |
| repeat_iter = repeat; |
| } |
| } |
| |
| return buffer; |
| } |
| |
| |
| static svn_error_t * |
| test_stream_compressed(apr_pool_t *pool) |
| { |
| #define NUM_TEST_STRINGS 5 |
| #define TEST_BUF_SIZE 10 |
| #define GENERATED_SIZE 20000 |
| |
| int i; |
| svn_stringbuf_t *bufs[NUM_TEST_STRINGS]; |
| apr_pool_t *subpool = svn_pool_create(pool); |
| |
| static const char * const strings[NUM_TEST_STRINGS - 1] = { |
| /* 0 */ |
| "", |
| /* 1 */ |
| "This is a string.", |
| /* 2 */ |
| "This is, by comparison to the previous string, a much longer string.", |
| /* 3 */ |
| "And if you thought that last string was long, you just wait until " |
| "I'm finished here. I mean, how can a string really claim to be long " |
| "when it fits on a single line of 80-columns? Give me a break. " |
| "Now, I'm not saying that I'm the longest string out there--far from " |
| "it--but I feel that it is safe to assume that I'm far longer than my " |
| "peers. And that demands some amount of respect, wouldn't you say?" |
| }; |
| |
| |
| for (i = 0; i < (NUM_TEST_STRINGS - 1); i++) |
| bufs[i] = svn_stringbuf_create(strings[i], pool); |
| |
| /* the last buffer is for the generated data */ |
| bufs[NUM_TEST_STRINGS - 1] = generate_test_bytes(GENERATED_SIZE, pool); |
| |
| for (i = 0; i < NUM_TEST_STRINGS; i++) |
| { |
| svn_stream_t *stream; |
| svn_stringbuf_t *origbuf, *inbuf, *outbuf; |
| char buf[TEST_BUF_SIZE]; |
| apr_size_t len; |
| |
| origbuf = bufs[i]; |
| inbuf = svn_stringbuf_create_empty(subpool); |
| outbuf = svn_stringbuf_create_empty(subpool); |
| |
| stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf, |
| subpool), |
| subpool); |
| len = origbuf->len; |
| SVN_ERR(svn_stream_write(stream, origbuf->data, &len)); |
| SVN_ERR(svn_stream_close(stream)); |
| |
| stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf, |
| subpool), |
| subpool); |
| len = TEST_BUF_SIZE; |
| while (len >= TEST_BUF_SIZE) |
| { |
| len = TEST_BUF_SIZE; |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| if (len > 0) |
| svn_stringbuf_appendbytes(inbuf, buf, len); |
| } |
| |
| if (! svn_stringbuf_compare(inbuf, origbuf)) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Got unexpected result."); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| svn_pool_clear(subpool); |
| } |
| |
| #undef NUM_TEST_STRINGS |
| #undef TEST_BUF_SIZE |
| #undef GENERATED_SIZE |
| |
| svn_pool_destroy(subpool); |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_tee(apr_pool_t *pool) |
| { |
| svn_stringbuf_t *test_bytes = generate_test_bytes(100, pool); |
| svn_stringbuf_t *output_buf1 = svn_stringbuf_create_empty(pool); |
| svn_stringbuf_t *output_buf2 = svn_stringbuf_create_empty(pool); |
| svn_stream_t *source_stream = svn_stream_from_stringbuf(test_bytes, pool); |
| svn_stream_t *output_stream1 = svn_stream_from_stringbuf(output_buf1, pool); |
| svn_stream_t *output_stream2 = svn_stream_from_stringbuf(output_buf2, pool); |
| svn_stream_t *tee_stream; |
| |
| tee_stream = svn_stream_tee(output_stream1, output_stream2, pool); |
| SVN_ERR(svn_stream_copy3(source_stream, tee_stream, NULL, NULL, pool)); |
| |
| if (!svn_stringbuf_compare(output_buf1, output_buf2)) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Duplicated streams did not match."); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_seek_file(apr_pool_t *pool) |
| { |
| static const char *file_data[2] = {"One", "Two"}; |
| svn_stream_t *stream; |
| svn_stringbuf_t *line; |
| svn_boolean_t eof; |
| apr_file_t *f; |
| static const char *fname = "test_stream_seek.txt"; |
| int j; |
| apr_status_t status; |
| static const char *NL = APR_EOL_STR; |
| svn_stream_mark_t *mark; |
| |
| status = apr_file_open(&f, fname, (APR_READ | APR_WRITE | APR_CREATE | |
| APR_TRUNCATE | APR_DELONCLOSE), APR_OS_DEFAULT, pool); |
| if (status != APR_SUCCESS) |
| return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot open '%s'", |
| fname); |
| |
| /* Create the file. */ |
| for (j = 0; j < 2; j++) |
| { |
| apr_size_t len; |
| |
| len = strlen(file_data[j]); |
| status = apr_file_write(f, file_data[j], &len); |
| if (status || len != strlen(file_data[j])) |
| return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, |
| "Cannot write to '%s'", fname); |
| len = strlen(NL); |
| status = apr_file_write(f, NL, &len); |
| if (status || len != strlen(NL)) |
| return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, |
| "Cannot write to '%s'", fname); |
| } |
| |
| /* Create a stream to read from the file. */ |
| stream = svn_stream_from_aprfile2(f, FALSE, pool); |
| SVN_ERR(svn_stream_reset(stream)); |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0); |
| /* Set a mark at the beginning of the second line of the file. */ |
| SVN_ERR(svn_stream_mark(stream, &mark, pool)); |
| /* Read the second line and then seek back to the mark. */ |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0); |
| SVN_ERR(svn_stream_seek(stream, mark)); |
| /* The next read should return the second line again. */ |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0); |
| /* The next read should return EOF. */ |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(eof); |
| |
| /* Go back to the beginning of the last line and try to skip it |
| * NOT including the EOL. */ |
| SVN_ERR(svn_stream_seek(stream, mark)); |
| SVN_ERR(svn_stream_skip(stream, strlen(file_data[1]))); |
| /* The remaining line should be empty */ |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(! eof && strcmp(line->data, "") == 0); |
| /* The next read should return EOF. */ |
| SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_seek_stringbuf(apr_pool_t *pool) |
| { |
| svn_stream_t *stream; |
| svn_stringbuf_t *stringbuf; |
| char buf[4]; |
| apr_size_t len; |
| svn_stream_mark_t *mark; |
| |
| stringbuf = svn_stringbuf_create("OneTwo", pool); |
| stream = svn_stream_from_stringbuf(stringbuf, pool); |
| len = 3; |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| buf[3] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "One"); |
| SVN_ERR(svn_stream_mark(stream, &mark, pool)); |
| len = 3; |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| buf[3] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "Two"); |
| SVN_ERR(svn_stream_seek(stream, mark)); |
| len = 3; |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| buf[3] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "Two"); |
| |
| /* Go back to the begin of last word and try to skip some of it */ |
| SVN_ERR(svn_stream_seek(stream, mark)); |
| SVN_ERR(svn_stream_skip(stream, 2)); |
| /* The remaining line should be empty */ |
| len = 3; |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| buf[len] = '\0'; |
| SVN_TEST_ASSERT(len == 1); |
| SVN_TEST_STRING_ASSERT(buf, "o"); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_seek_translated(apr_pool_t *pool) |
| { |
| svn_stream_t *stream, *translated_stream; |
| svn_stringbuf_t *stringbuf; |
| char buf[44]; /* strlen("One$MyKeyword: my keyword was expanded $Two") + \0 */ |
| apr_size_t len; |
| svn_stream_mark_t *mark; |
| apr_hash_t *keywords; |
| svn_string_t *keyword_val; |
| |
| keywords = apr_hash_make(pool); |
| keyword_val = svn_string_create("my keyword was expanded", pool); |
| apr_hash_set(keywords, "MyKeyword", APR_HASH_KEY_STRING, keyword_val); |
| stringbuf = svn_stringbuf_create("One$MyKeyword$Two", pool); |
| stream = svn_stream_from_stringbuf(stringbuf, pool); |
| translated_stream = svn_subst_stream_translated(stream, APR_EOL_STR, |
| FALSE, keywords, TRUE, pool); |
| /* Seek from outside of keyword to inside of keyword. */ |
| len = 25; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 25); |
| buf[25] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "One$MyKeyword: my keyword"); |
| SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); |
| SVN_ERR(svn_stream_reset(translated_stream)); |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| len = 4; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 4); |
| buf[4] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, " was"); |
| |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| SVN_ERR(svn_stream_skip(translated_stream, 2)); |
| len = 2; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 2); |
| buf[len] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "as"); |
| |
| /* Seek from inside of keyword to inside of keyword. */ |
| SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); |
| len = 9; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 9); |
| buf[9] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, " expanded"); |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| len = 9; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 9); |
| buf[9] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, " expanded"); |
| |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| SVN_ERR(svn_stream_skip(translated_stream, 6)); |
| len = 3; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 3); |
| buf[len] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "ded"); |
| |
| /* Seek from inside of keyword to outside of keyword. */ |
| SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); |
| len = 4; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 4); |
| buf[4] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, " $Tw"); |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| len = 4; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 4); |
| buf[4] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, " $Tw"); |
| |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| SVN_ERR(svn_stream_skip(translated_stream, 2)); |
| len = 2; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 2); |
| buf[len] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "Tw"); |
| |
| /* Seek from outside of keyword to outside of keyword. */ |
| SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); |
| len = 1; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 1); |
| buf[1] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "o"); |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| len = 1; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 1); |
| buf[1] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, "o"); |
| |
| SVN_ERR(svn_stream_seek(translated_stream, mark)); |
| SVN_ERR(svn_stream_skip(translated_stream, 2)); |
| len = 1; |
| SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); |
| SVN_TEST_ASSERT(len == 0); |
| buf[len] = '\0'; |
| SVN_TEST_STRING_ASSERT(buf, ""); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_readonly(apr_pool_t *pool) |
| { |
| const char *path; |
| apr_finfo_t finfo; |
| svn_boolean_t read_only; |
| apr_int32_t wanted = APR_FINFO_SIZE | APR_FINFO_MTIME | APR_FINFO_TYPE |
| | APR_FINFO_LINK | APR_FINFO_PROT; |
| |
| |
| SVN_ERR(svn_io_open_unique_file3(NULL, &path, NULL, |
| svn_io_file_del_on_pool_cleanup, |
| pool, pool)); |
| |
| /* File should be writable */ |
| SVN_ERR(svn_io_stat(&finfo, path, wanted, pool)); |
| SVN_ERR(svn_io__is_finfo_read_only(&read_only, &finfo, pool)); |
| SVN_TEST_ASSERT(!read_only); |
| |
| /* Set read only */ |
| SVN_ERR(svn_io_set_file_read_only(path, FALSE, pool)); |
| |
| /* File should be read only */ |
| SVN_ERR(svn_io_stat(&finfo, path, wanted, pool)); |
| SVN_ERR(svn_io__is_finfo_read_only(&read_only, &finfo, pool)); |
| SVN_TEST_ASSERT(read_only); |
| |
| /* Set writable */ |
| SVN_ERR(svn_io_set_file_read_write(path, FALSE, pool)); |
| |
| /* File should be writable */ |
| SVN_ERR(svn_io_stat(&finfo, path, wanted, pool)); |
| SVN_ERR(svn_io__is_finfo_read_only(&read_only, &finfo, pool)); |
| SVN_TEST_ASSERT(!read_only); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_compressed_empty_file(apr_pool_t *pool) |
| { |
| svn_stream_t *stream, *empty_file_stream; |
| char buf[1]; |
| apr_size_t len; |
| |
| /* Reading an empty file with a compressed stream should not error. */ |
| SVN_ERR(svn_stream_open_unique(&empty_file_stream, NULL, NULL, |
| svn_io_file_del_on_pool_cleanup, |
| pool, pool)); |
| stream = svn_stream_compressed(empty_file_stream, pool); |
| len = sizeof(buf); |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| if (len > 0) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Got unexpected result."); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_base64(apr_pool_t *pool) |
| { |
| svn_stream_t *stream; |
| svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool); |
| svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool); |
| int i; |
| static const char *strings[] = { |
| "fairly boring test data... blah blah", |
| "A", |
| "abc", |
| "012345679", |
| NULL |
| }; |
| |
| /* Test svn_base64_encode2() with BREAK_LINES=FALSE. */ |
| stream = svn_stream_from_stringbuf(actual, pool); |
| stream = svn_base64_decode(stream, pool); |
| stream = svn_base64_encode2(stream, TRUE, pool); |
| |
| for (i = 0; strings[i]; i++) |
| { |
| apr_size_t len = strlen(strings[i]); |
| |
| svn_stringbuf_appendbytes(expected, strings[i], len); |
| SVN_ERR(svn_stream_write(stream, strings[i], &len)); |
| } |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| SVN_TEST_STRING_ASSERT(actual->data, expected->data); |
| |
| /* Test svn_base64_encode2() with BREAK_LINES=FALSE. */ |
| stream = svn_stream_from_stringbuf(actual, pool); |
| stream = svn_base64_decode(stream, pool); |
| stream = svn_base64_encode2(stream, FALSE, pool); |
| |
| for (i = 0; strings[i]; i++) |
| { |
| apr_size_t len = strlen(strings[i]); |
| |
| svn_stringbuf_appendbytes(expected, strings[i], len); |
| SVN_ERR(svn_stream_write(stream, strings[i], &len)); |
| } |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| SVN_TEST_STRING_ASSERT(actual->data, expected->data); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| /* This test doesn't test much unless run under valgrind when it |
| triggers the problem reported here: |
| |
| http://mail-archives.apache.org/mod_mbox/subversion-dev/201202.mbox/%3C87sjik3m8q.fsf@stat.home.lan%3E |
| |
| The two data writes caused the base 64 code to allocate a buffer |
| that was a byte short but exactly matched a stringbuf blocksize. |
| That meant the stringbuf didn't overallocate and a write beyond |
| the end of the buffer occurred. |
| */ |
| static svn_error_t * |
| test_stream_base64_2(apr_pool_t *pool) |
| { |
| const struct data_t { |
| const char *encoded1; |
| const char *encoded2; |
| } data[] = { |
| { |
| "MTI", |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "A23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "B23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "C23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "D23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "E23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "F23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "G23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "H23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "I23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D123456789E" |
| "623456789A123456789B123456789C123456789D123456789E" |
| "723456789A123456789B123456789C123456789D123456789E" |
| "823456789A123456789B123456789C123456789D123456789E" |
| "923456789A123456789B123456789C123456789D123456789E" |
| "J23456789A123456789B123456789C123456789D123456789E" |
| "123456789A123456789B123456789C123456789D123456789E" |
| "223456789A123456789B123456789C123456789D123456789E" |
| "323456789A123456789B123456789C123456789D123456789E" |
| "423456789A123456789B123456789C123456789D123456789E" |
| "523456789A123456789B123456789C123456789D12345" |
| }, |
| { |
| NULL, |
| NULL, |
| }, |
| }; |
| int i; |
| |
| /* Test svn_base64_encode2() with BREAK_LINES=TRUE. */ |
| for (i = 0; data[i].encoded1; i++) |
| { |
| apr_size_t len1 = strlen(data[i].encoded1); |
| |
| svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool); |
| svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool); |
| svn_stream_t *stream = svn_stream_from_stringbuf(actual, pool); |
| |
| stream = svn_base64_encode2(stream, TRUE, pool); |
| stream = svn_base64_decode(stream, pool); |
| |
| SVN_ERR(svn_stream_write(stream, data[i].encoded1, &len1)); |
| svn_stringbuf_appendbytes(expected, data[i].encoded1, len1); |
| |
| if (data[i].encoded2) |
| { |
| apr_size_t len2 = strlen(data[i].encoded2); |
| SVN_ERR(svn_stream_write(stream, data[i].encoded2, &len2)); |
| svn_stringbuf_appendbytes(expected, data[i].encoded2, len2); |
| } |
| |
| SVN_ERR(svn_stream_close(stream)); |
| } |
| |
| /* Test svn_base64_encode2() with BREAK_LINES=FALSE. */ |
| for (i = 0; data[i].encoded1; i++) |
| { |
| apr_size_t len1 = strlen(data[i].encoded1); |
| |
| svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool); |
| svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool); |
| svn_stream_t *stream = svn_stream_from_stringbuf(actual, pool); |
| |
| stream = svn_base64_encode2(stream, FALSE, pool); |
| stream = svn_base64_decode(stream, pool); |
| |
| SVN_ERR(svn_stream_write(stream, data[i].encoded1, &len1)); |
| svn_stringbuf_appendbytes(expected, data[i].encoded1, len1); |
| |
| if (data[i].encoded2) |
| { |
| apr_size_t len2 = strlen(data[i].encoded2); |
| SVN_ERR(svn_stream_write(stream, data[i].encoded2, &len2)); |
| svn_stringbuf_appendbytes(expected, data[i].encoded2, len2); |
| } |
| |
| SVN_ERR(svn_stream_close(stream)); |
| } |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stringbuf_from_stream(apr_pool_t *pool) |
| { |
| const char *test_cases[] = |
| { |
| "", |
| "x", |
| "this string is longer than the default 64 minimum block size used" |
| "by the function under test", |
| NULL |
| }; |
| |
| const char **test_case; |
| for (test_case = test_cases; *test_case; ++test_case) |
| { |
| svn_stringbuf_t *result1, *result2, *result3, *result4; |
| svn_stringbuf_t *original = svn_stringbuf_create(*test_case, pool); |
| |
| svn_stream_t *stream1 = svn_stream_from_stringbuf(original, pool); |
| svn_stream_t *stream2 = svn_stream_from_stringbuf(original, pool); |
| |
| SVN_ERR(svn_stringbuf_from_stream(&result1, stream1, 0, pool)); |
| SVN_ERR(svn_stringbuf_from_stream(&result2, stream1, 0, pool)); |
| SVN_ERR(svn_stringbuf_from_stream(&result3, stream2, original->len, |
| pool)); |
| SVN_ERR(svn_stringbuf_from_stream(&result4, stream2, original->len, |
| pool)); |
| |
| /* C-string contents must match */ |
| SVN_TEST_STRING_ASSERT(result1->data, original->data); |
| SVN_TEST_STRING_ASSERT(result2->data, ""); |
| SVN_TEST_STRING_ASSERT(result3->data, original->data); |
| SVN_TEST_STRING_ASSERT(result4->data, ""); |
| |
| /* assumed length must match */ |
| SVN_TEST_ASSERT(result1->len == original->len); |
| SVN_TEST_ASSERT(result2->len == 0); |
| SVN_TEST_ASSERT(result3->len == original->len); |
| SVN_TEST_ASSERT(result4->len == 0); |
| } |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| empty_read_full_fn(void *baton, char *buffer, apr_size_t *len) |
| { |
| *len = 0; |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_compressed_read_full(apr_pool_t *pool) |
| { |
| svn_stream_t *stream, *empty_stream; |
| char buf[1]; |
| apr_size_t len; |
| |
| /* Reading an empty stream with read_full only support should not error. */ |
| empty_stream = svn_stream_create(NULL, pool); |
| |
| /* Create stream with only full read support. */ |
| svn_stream_set_read2(empty_stream, NULL, empty_read_full_fn); |
| |
| stream = svn_stream_compressed(empty_stream, pool); |
| len = sizeof(buf); |
| SVN_ERR(svn_stream_read_full(stream, buf, &len)); |
| if (len > 0) |
| return svn_error_create(SVN_ERR_TEST_FAILED, NULL, |
| "Got unexpected result."); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_checksum(apr_pool_t *pool) |
| { |
| svn_string_t *str = |
| svn_string_create("The quick brown fox jumps over the lazy dog", pool); |
| svn_checksum_t *actual; |
| |
| SVN_ERR(svn_stream_contents_checksum(&actual, |
| svn_stream_from_string(str, pool), |
| svn_checksum_md5, pool, pool)); |
| SVN_TEST_STRING_ASSERT("9e107d9d372bb6826bd81d3542a419d6", |
| svn_checksum_to_cstring(actual, pool)); |
| |
| SVN_ERR(svn_stream_contents_checksum(&actual, |
| svn_stream_from_string(str, pool), |
| svn_checksum_sha1, pool, pool)); |
| SVN_TEST_STRING_ASSERT("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", |
| svn_checksum_to_cstring(actual, pool)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_readline_file(const char *testname, |
| const char *eol, |
| apr_pool_t *pool) |
| { |
| const char *tmp_dir; |
| const char *tmp_file; |
| svn_stream_t *stream; |
| svn_stringbuf_t *line; |
| svn_boolean_t eof; |
| static const char long_line[] = |
| "The quick brown fox jumps over the lazy dog, and " |
| "jackdaws love my big sphinx of quartz, and " |
| "pack my box with five dozen liquor jugs."; |
| |
| SVN_ERR(svn_dirent_get_absolute(&tmp_dir, testname, pool)); |
| SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); |
| SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); |
| svn_test_add_dir_cleanup(tmp_dir); |
| |
| /* Test 1: Read empty file. */ |
| tmp_file = svn_dirent_join(tmp_dir, "empty", pool); |
| SVN_ERR(svn_io_file_create(tmp_file, "", pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| /* Test 2: Read empty line. */ |
| tmp_file = svn_dirent_join(tmp_dir, "empty-line", pool); |
| SVN_ERR(svn_io_file_create(tmp_file, eol, pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(!eof); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| /* Test 3: Read two lines. */ |
| tmp_file = svn_dirent_join(tmp_dir, "lines", pool); |
| SVN_ERR(svn_io_file_create(tmp_file, |
| apr_pstrcat(pool, |
| "first", eol, "second", eol, |
| SVN_VA_NULL), |
| pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 5); |
| SVN_TEST_STRING_ASSERT(line->data, "first"); |
| SVN_TEST_ASSERT(!eof); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 6); |
| SVN_TEST_STRING_ASSERT(line->data, "second"); |
| SVN_TEST_ASSERT(!eof); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| /* Test 4: Content without end-of-line. */ |
| tmp_file = svn_dirent_join(tmp_dir, "no-eol", pool); |
| SVN_ERR(svn_io_file_create(tmp_file, "text", pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 4); |
| SVN_TEST_STRING_ASSERT(line->data, "text"); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| /* Test 5: Read long line. */ |
| tmp_file = svn_dirent_join(tmp_dir, "long-line", pool); |
| SVN_ERR(svn_io_file_create(tmp_file, |
| apr_pstrcat(pool, long_line, eol, SVN_VA_NULL), |
| pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == strlen(long_line)); |
| SVN_TEST_STRING_ASSERT(line->data, long_line); |
| SVN_TEST_ASSERT(!eof); |
| |
| SVN_ERR(svn_stream_readline(stream, &line, eol, &eof, pool)); |
| SVN_TEST_ASSERT(line->len == 0); |
| SVN_TEST_STRING_ASSERT(line->data, ""); |
| SVN_TEST_ASSERT(eof); |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_readline_file_lf(apr_pool_t *pool) |
| { |
| SVN_ERR(test_stream_readline_file("test_stream_readline_file_lf", |
| "\n", pool)); |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_readline_file_crlf(apr_pool_t *pool) |
| { |
| SVN_ERR(test_stream_readline_file("test_stream_readline_file_crlf", |
| "\r\n", pool)); |
| return SVN_NO_ERROR; |
| } |
| |
| static svn_error_t * |
| test_stream_readline_file_nul(apr_pool_t *pool) |
| { |
| /* Test is written based on the problem report in |
| https://lists.apache.org/thread.html/c96eb5618ac0bf6e083345e0fdcdcf834e30913f26eabe6ada7bab62@%3Cusers.subversion.apache.org%3E |
| where the user had an OOM when calling `svndumpfilter` with |
| a (most likely) invalid dump containing nul bytes. |
| */ |
| const char data[] = |
| { |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', |
| 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n', 'a', '\0', '\n' |
| }; |
| const char *tmp_dir; |
| const char *tmp_file; |
| svn_stream_t *stream; |
| |
| SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_stream_readline_file_nul", pool)); |
| SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); |
| SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); |
| svn_test_add_dir_cleanup(tmp_dir); |
| |
| tmp_file = svn_dirent_join(tmp_dir, "file", pool); |
| SVN_ERR(svn_io_file_create_bytes(tmp_file, data, sizeof(data), pool)); |
| SVN_ERR(svn_stream_open_readonly(&stream, tmp_file, pool, pool)); |
| |
| while (1) |
| { |
| svn_boolean_t eof; |
| svn_stringbuf_t *line; |
| |
| SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool)); |
| if (eof) |
| break; |
| |
| /* Don't check the contents of the `line` here, at least for now. |
| |
| In other words, we just test that this case does not crash or cause |
| unexpected errors. The reason is that currently our `readline_fn` |
| implementations have inconsistent behavior when dealing with \0 bytes, |
| handling those differently, either in strchr() or memchr() styles. |
| |
| Once we make them consistent (or even decide to bail out with an error |
| for \0), this part of the test should start properly checking `data`; |
| maybe also for non-file streams. |
| */ |
| } |
| |
| SVN_ERR(svn_stream_close(stream)); |
| |
| return SVN_NO_ERROR; |
| } |
| |
| /* The test table. */ |
| |
| static int max_threads = 1; |
| |
| static struct svn_test_descriptor_t test_funcs[] = |
| { |
| SVN_TEST_NULL, |
| SVN_TEST_PASS2(test_stream_from_string, |
| "test svn_stream_from_string"), |
| SVN_TEST_PASS2(test_stream_compressed, |
| "test compressed streams"), |
| SVN_TEST_PASS2(test_stream_tee, |
| "test 'tee' streams"), |
| SVN_TEST_PASS2(test_stream_seek_file, |
| "test stream seeking for files"), |
| SVN_TEST_PASS2(test_stream_seek_stringbuf, |
| "test stream seeking for stringbufs"), |
| SVN_TEST_PASS2(test_stream_seek_translated, |
| "test stream seeking for translated streams"), |
| SVN_TEST_PASS2(test_readonly, |
| "test setting a file readonly"), |
| SVN_TEST_PASS2(test_stream_compressed_empty_file, |
| "test compressed streams with empty files"), |
| SVN_TEST_PASS2(test_stream_base64, |
| "test base64 encoding/decoding streams"), |
| SVN_TEST_PASS2(test_stream_base64_2, |
| "base64 decoding allocation problem"), |
| SVN_TEST_PASS2(test_stringbuf_from_stream, |
| "test svn_stringbuf_from_stream"), |
| SVN_TEST_PASS2(test_stream_compressed_read_full, |
| "test compression for streams without partial read"), |
| SVN_TEST_PASS2(test_stream_checksum, |
| "test svn_stream_contents_checksum()"), |
| SVN_TEST_PASS2(test_stream_readline_file_lf, |
| "test reading LF-terminated lines from file"), |
| SVN_TEST_PASS2(test_stream_readline_file_crlf, |
| "test reading CRLF-terminated lines from file"), |
| SVN_TEST_PASS2(test_stream_readline_file_nul, |
| "test reading line from file with nul bytes"), |
| SVN_TEST_NULL |
| }; |
| |
| SVN_TEST_MAIN |