blob: 7eae5e12aaf9f11ba6ab7acd574004548061d4a6 [file] [log] [blame]
/**
* 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
*
* https://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 "Exception.hh"
#include "Stream.hh"
#include "boost/filesystem.hpp"
#include <boost/test/included/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
namespace avro {
namespace stream {
struct CheckEmpty1 {
void operator()(InputStream &is) {
const uint8_t *d;
size_t n;
BOOST_CHECK(!is.next(&d, &n));
}
};
struct CheckEmpty2 {
void operator()(InputStream &is) {
StreamReader r;
r.reset(is);
BOOST_CHECK_THROW(r.read(), Exception);
}
};
struct TestData {
size_t chunkSize;
size_t dataSize;
};
struct Fill1 {
void operator()(OutputStream &os, size_t len) {
StreamWriter w;
w.reset(os);
for (size_t i = 0; i < len; ++i) {
w.write(i % 10 + '0');
}
w.flush();
}
};
struct Fill2 {
void operator()(OutputStream &os, size_t len) {
for (size_t i = 0; i < len;) {
uint8_t *b;
size_t n;
os.next(&b, &n);
size_t j = 0;
for (; i < len && j < n; ++j, ++i, ++b) {
*b = i % 10 + '0';
}
if (i == len) {
os.backup(n - j);
}
}
os.flush();
}
};
struct Verify1 {
void operator()(InputStream &is, size_t dataSize) {
StreamReader r;
r.reset(is);
for (size_t i = 0; i < dataSize; ++i) {
BOOST_CHECK_EQUAL(i % 10 + '0', r.read());
}
BOOST_CHECK_THROW(r.read(), Exception);
}
};
struct Verify2 {
void operator()(InputStream &is, size_t len) {
const uint8_t *b;
size_t n;
for (size_t i = 0; i < len;) {
BOOST_REQUIRE(is.next(&b, &n));
size_t j = 0;
for (; i < len && j < n; ++j, ++i, ++b) {
BOOST_CHECK_EQUAL(*b, i % 10 + '0');
}
BOOST_CHECK_EQUAL(j, n);
}
BOOST_CHECK(!is.next(&b, &n));
}
};
template<typename V>
void testEmpty_memoryStream() {
std::unique_ptr<OutputStream> os = memoryOutputStream();
std::unique_ptr<InputStream> is = memoryInputStream(*os);
V()
(*is);
}
template<typename F, typename V>
void testNonEmpty_memoryStream(const TestData &td) {
std::unique_ptr<OutputStream> os = memoryOutputStream(td.chunkSize);
F()
(*os, td.dataSize);
std::unique_ptr<InputStream> is = memoryInputStream(*os);
V()
(*is, td.dataSize);
}
void testNonEmpty2(const TestData &td) {
std::vector<uint8_t> v;
for (size_t i = 0; i < td.dataSize; ++i) {
v.push_back(i % 10 + '0');
}
uint8_t v2 = 0;
std::unique_ptr<InputStream> is = memoryInputStream(v.empty() ? &v2 : &v[0], v.size());
Verify1()(*is, td.dataSize);
}
static const char filename[] = "test_str.bin";
struct FileRemover {
const boost::filesystem::path file;
explicit FileRemover(const char *fn) : file(fn) {}
~FileRemover() { boost::filesystem::remove(file); }
};
template<typename V>
void testEmpty_fileStream() {
FileRemover fr(filename);
{
std::unique_ptr<OutputStream> os = fileOutputStream(filename);
}
std::unique_ptr<InputStream> is = fileInputStream(filename);
V()
(*is);
}
template<typename F, typename V>
void testNonEmpty_fileStream(const TestData &td) {
FileRemover fr(filename);
{
std::unique_ptr<OutputStream> os = fileOutputStream(filename,
td.chunkSize);
F()
(*os, td.dataSize);
}
std::unique_ptr<InputStream> is = fileInputStream(filename, td.chunkSize);
V()
(*is, td.dataSize);
}
TestData data[] = {
{100, 0},
{100, 1},
{100, 10},
{100, 100},
{100, 101},
{100, 1000},
{100, 1024}};
} // namespace stream
} // namespace avro
boost::unit_test::test_suite *
init_unit_test_suite(int /*argc*/, char * /*argv*/[]) {
auto *ts = BOOST_TEST_SUITE("Avro C++ unit test suite for streams");
ts->add(BOOST_TEST_CASE(
&avro::stream::testEmpty_memoryStream<avro::stream::CheckEmpty1>));
ts->add(BOOST_TEST_CASE(
&avro::stream::testEmpty_memoryStream<avro::stream::CheckEmpty2>));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_memoryStream<avro::stream::Fill1,
avro::stream::Verify1>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_memoryStream<avro::stream::Fill2,
avro::stream::Verify1>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_memoryStream<avro::stream::Fill2,
avro::stream::Verify2>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_PARAM_TEST_CASE(&avro::stream::testNonEmpty2,
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_TEST_CASE(
&avro::stream::testEmpty_fileStream<avro::stream::CheckEmpty1>));
ts->add(BOOST_TEST_CASE(
&avro::stream::testEmpty_fileStream<avro::stream::CheckEmpty2>));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_fileStream<avro::stream::Fill1,
avro::stream::Verify1>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_fileStream<avro::stream::Fill2,
avro::stream::Verify1>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
ts->add(BOOST_PARAM_TEST_CASE(
(&avro::stream::testNonEmpty_fileStream<avro::stream::Fill2,
avro::stream::Verify2>),
avro::stream::data,
avro::stream::data + sizeof(avro::stream::data) / sizeof(avro::stream::data[0])));
return ts;
}