/* * Copyright (C) 2015 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE core #include "bytes_ostream.hh" #include #include "serializer_impl.hh" void append_sequence(bytes_ostream& buf, int count) { for (int i = 0; i < count; i++) { ser::serialize(buf, i); } } void assert_sequence(bytes_ostream& buf, int count) { auto in = ser::as_input_stream(buf.linearize()); assert(buf.size() == count * sizeof(int)); for (int i = 0; i < count; i++) { auto val = ser::deserialize(in, boost::type()); BOOST_REQUIRE_EQUAL(val, i); } } BOOST_AUTO_TEST_CASE(test_appended_data_is_retained) { bytes_ostream buf; append_sequence(buf, 1024); assert_sequence(buf, 1024); } BOOST_AUTO_TEST_CASE(test_copy_constructor) { bytes_ostream buf; append_sequence(buf, 1024); bytes_ostream buf2(buf); BOOST_REQUIRE(buf.size() == 1024 * sizeof(int)); BOOST_REQUIRE(buf2.size() == 1024 * sizeof(int)); BOOST_REQUIRE(buf2.is_linearized()); assert_sequence(buf, 1024); assert_sequence(buf2, 1024); } BOOST_AUTO_TEST_CASE(test_copy_assignment) { bytes_ostream buf; append_sequence(buf, 512); bytes_ostream buf2; append_sequence(buf2, 1024); buf2 = buf; BOOST_REQUIRE(buf.size() == 512 * sizeof(int)); BOOST_REQUIRE(buf2.size() == 512 * sizeof(int)); BOOST_REQUIRE(buf2.is_linearized()); assert_sequence(buf, 512); assert_sequence(buf2, 512); } BOOST_AUTO_TEST_CASE(test_move_assignment) { bytes_ostream buf; append_sequence(buf, 512); bytes_ostream buf2; append_sequence(buf2, 1024); buf2 = std::move(buf); BOOST_REQUIRE(buf.size() == 0); BOOST_REQUIRE(buf2.size() == 512 * sizeof(int)); assert_sequence(buf2, 512); } BOOST_AUTO_TEST_CASE(test_move_constructor) { bytes_ostream buf; append_sequence(buf, 1024); bytes_ostream buf2(std::move(buf)); BOOST_REQUIRE(buf.size() == 0); BOOST_REQUIRE(buf2.size() == 1024 * sizeof(int)); assert_sequence(buf2, 1024); } BOOST_AUTO_TEST_CASE(test_size) { bytes_ostream buf; append_sequence(buf, 1024); BOOST_REQUIRE_EQUAL(buf.size(), sizeof(int) * 1024); } BOOST_AUTO_TEST_CASE(test_is_linearized) { bytes_ostream buf; BOOST_REQUIRE(buf.is_linearized()); ser::serialize(buf, 1); BOOST_REQUIRE(buf.is_linearized()); append_sequence(buf, 1024); BOOST_REQUIRE(!buf.is_linearized()); // probably } BOOST_AUTO_TEST_CASE(test_view) { bytes_ostream buf; ser::serialize(buf, 1); BOOST_REQUIRE(buf.is_linearized()); auto in = ser::as_input_stream(buf.view()); BOOST_REQUIRE_EQUAL(1, ser::deserialize(in, boost::type())); } BOOST_AUTO_TEST_CASE(test_writing_blobs) { bytes_ostream buf; bytes b("hello"); bytes_view b_view(b.begin(), b.size()); buf.write(b_view); BOOST_REQUIRE(buf.linearize() == b_view); } BOOST_AUTO_TEST_CASE(test_writing_large_blobs) { bytes_ostream buf; bytes b(bytes::initialized_later(), 1024); std::fill(b.begin(), b.end(), 7); bytes_view b_view(b.begin(), b.size()); buf.write(b_view); auto buf_view = buf.linearize(); BOOST_REQUIRE(std::all_of(buf_view.begin(), buf_view.end(), [] (auto&& c) { return c == 7; })); } BOOST_AUTO_TEST_CASE(test_fragment_iteration) { int count = 64*1024; bytes_ostream buf; append_sequence(buf, count); bytes_ostream buf2; for (bytes_view frag : buf.fragments()) { buf2.write(frag); } // If this fails, we will only have one fragment, and the test will be weak. // Bump up the 'count' if this is triggered. assert(!buf2.is_linearized()); assert_sequence(buf2, count); } BOOST_AUTO_TEST_CASE(test_writing_empty_blobs) { bytes_ostream buf; bytes b; buf.write(b); BOOST_REQUIRE(buf.size() == 0); BOOST_REQUIRE(buf.linearize().empty()); } BOOST_AUTO_TEST_CASE(test_retraction_to_initial_state) { bytes_ostream buf; auto pos = buf.pos(); ser::serialize(buf, 1); buf.retract(pos); BOOST_REQUIRE(buf.size() == 0); BOOST_REQUIRE(buf.linearize().empty()); } BOOST_AUTO_TEST_CASE(test_retraction_to_the_same_chunk) { bytes_ostream buf; ser::serialize(buf, 1); ser::serialize(buf, 2); auto pos = buf.pos(); ser::serialize(buf, 3); ser::serialize(buf, 4); buf.retract(pos); BOOST_REQUIRE(buf.size() == sizeof(int) * 2); auto in = ser::as_input_stream(buf.view()); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 1); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 2); BOOST_REQUIRE(in.size() == 0); } BOOST_AUTO_TEST_CASE(test_no_op_retraction) { bytes_ostream buf; ser::serialize(buf, 1); ser::serialize(buf, 2); auto pos = buf.pos(); buf.retract(pos); BOOST_REQUIRE(buf.size() == sizeof(int) * 2); auto in = ser::as_input_stream(buf.view()); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 1); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 2); BOOST_REQUIRE(in.size() == 0); } BOOST_AUTO_TEST_CASE(test_retraction_discarding_chunks) { bytes_ostream buf; ser::serialize(buf, 1); auto pos = buf.pos(); append_sequence(buf, 64*1024); buf.retract(pos); BOOST_REQUIRE(buf.size() == sizeof(int)); auto in = ser::as_input_stream(buf.view()); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 1); BOOST_REQUIRE(in.size() == 0); } BOOST_AUTO_TEST_CASE(test_writing_placeholders) { bytes_ostream buf; auto ph = buf.write_place_holder(); ser::serialize(buf, 2); auto ph_stream = ph.get_stream(); ser::serialize(ph_stream, 1); auto in = ser::as_input_stream(buf.view()); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 1); BOOST_REQUIRE_EQUAL(ser::deserialize(in, boost::type()), 2); BOOST_REQUIRE(in.size() == 0); } BOOST_AUTO_TEST_CASE(test_append_big_and_small_chunks) { bytes_ostream small; append_sequence(small, 12); bytes_ostream big; append_sequence(big, 513); bytes_ostream buf; buf.append(big); buf.append(small); buf.append(big); buf.append(small); }