406 lines
11 KiB
C++
406 lines
11 KiB
C++
/***
|
|
* ==++==
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed 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.
|
|
*
|
|
* ==--==
|
|
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
|
*
|
|
* Basic tests for async output stream operations.
|
|
*
|
|
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
****/
|
|
#include "stdafx.h"
|
|
|
|
using namespace concurrency::streams;
|
|
|
|
#if defined(__cplusplus_winrt)
|
|
using namespace Windows::Storage;
|
|
#endif
|
|
|
|
namespace tests { namespace functional { namespace streams {
|
|
|
|
using namespace utility;
|
|
using namespace ::pplx;
|
|
|
|
//
|
|
// The following two functions will help mask the differences between non-WinRT environments and
|
|
// WinRT: on the latter, a file path is typically not used to open files. Rather, a UI element is used
|
|
// to get a 'StorageFile' reference and you go from there. However, to test the library properly,
|
|
// we need to get a StorageFile reference somehow, and one way to do that is to create all the files
|
|
// used in testing in the Documents folder.
|
|
//
|
|
template<typename _CharType>
|
|
pplx::task<concurrency::streams::basic_ostream<_CharType>> OPENSTR_W(const utility::string_t &name, std::ios_base::openmode mode = std::ios_base::out)
|
|
{
|
|
#if !defined(__cplusplus_winrt)
|
|
return concurrency::streams::file_stream<_CharType>::open_ostream(name, mode);
|
|
#else
|
|
auto file = pplx::create_task(
|
|
KnownFolders::DocumentsLibrary->CreateFileAsync(
|
|
ref new Platform::String(name.c_str()), CreationCollisionOption::ReplaceExisting)).get();
|
|
|
|
return concurrency::streams::file_stream<_CharType>::open_ostream(file, mode);
|
|
#endif
|
|
}
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4100) // Because of '_Prot' in WinRT builds.
|
|
#endif
|
|
template<typename _CharType>
|
|
pplx::task<concurrency::streams::basic_istream<_CharType>> OPENSTR_R(const utility::string_t &name, std::ios_base::openmode mode = std::ios_base::in)
|
|
{
|
|
#if !defined(__cplusplus_winrt)
|
|
return concurrency::streams::file_stream<_CharType>::open_istream(name, mode);
|
|
#else
|
|
auto file = pplx::create_task(
|
|
KnownFolders::DocumentsLibrary->GetFileAsync(
|
|
ref new Platform::String(name.c_str()))).get();
|
|
|
|
return concurrency::streams::file_stream<_CharType>::open_istream(file, mode);
|
|
#endif
|
|
}
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
SUITE(ostream_tests)
|
|
{
|
|
|
|
TEST(BasicTest1)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("BasicTest1.txt"));
|
|
auto basic_stream = open.get();
|
|
VERIFY_IS_TRUE(basic_stream.can_seek());
|
|
auto a = basic_stream.print(10);
|
|
auto b = basic_stream.print("-suffix");
|
|
(a && b).wait();
|
|
auto cls = basic_stream.close();
|
|
cls.get();
|
|
VERIFY_IS_TRUE(cls.is_done());
|
|
}
|
|
|
|
TEST(BasicTest2)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("BasicTest2.txt"));
|
|
|
|
auto cls =
|
|
open.then(
|
|
[](pplx::task<concurrency::streams::ostream> op) -> pplx::task<void>
|
|
{
|
|
auto basic_stream = op.get();
|
|
auto a = basic_stream.print(10);
|
|
auto b = basic_stream.print("-suffix");
|
|
(a && b).wait();
|
|
return basic_stream.close();
|
|
});
|
|
|
|
cls.get();
|
|
|
|
VERIFY_IS_TRUE(cls.is_done());
|
|
}
|
|
|
|
|
|
TEST(WriteSingleCharTest2)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("WriteSingleCharStrTest1.txt"));
|
|
auto stream = open.get();
|
|
|
|
VERIFY_IS_TRUE(open.is_done());
|
|
|
|
bool elements_equal = true;
|
|
|
|
for (uint8_t ch = 'a'; ch <= 'z'; ch++)
|
|
{
|
|
elements_equal = elements_equal && (ch == stream.write(ch).get());
|
|
}
|
|
|
|
VERIFY_IS_TRUE(elements_equal);
|
|
|
|
auto close = stream.close();
|
|
close.get();
|
|
|
|
VERIFY_IS_TRUE(close.is_done());
|
|
}
|
|
|
|
TEST(WriteBufferTest1)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("WriteBufferStrTest1.txt"));
|
|
auto stream = open.get();
|
|
|
|
VERIFY_IS_TRUE(open.is_done());
|
|
|
|
std::vector<uint8_t> vect;
|
|
|
|
for (char ch = 'a'; ch <= 'z'; ch++)
|
|
{
|
|
vect.push_back(ch);
|
|
}
|
|
|
|
size_t vsz = vect.size();
|
|
|
|
concurrency::streams::container_stream<std::vector<uint8_t>>::buffer_type txtbuf(std::move(vect), std::ios_base::in);
|
|
|
|
VERIFY_ARE_EQUAL(stream.write(txtbuf, vsz).get(), vsz);
|
|
|
|
auto close = stream.close();
|
|
close.get();
|
|
|
|
VERIFY_IS_TRUE(close.is_done());
|
|
}
|
|
|
|
TEST(WriteBufferAndSyncTest1)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("WriteBufferAndSyncStrTest1.txt"));
|
|
auto stream = open.get();
|
|
|
|
VERIFY_IS_TRUE(open.is_done());
|
|
|
|
std::vector<char> vect;
|
|
|
|
for (char ch = 'a'; ch <= 'z'; ch++)
|
|
{
|
|
vect.push_back(ch);
|
|
}
|
|
|
|
size_t vsz = vect.size();
|
|
concurrency::streams::rawptr_buffer<uint8_t> txtbuf(reinterpret_cast<const uint8_t*>(&vect[0]), vsz);
|
|
|
|
auto write = stream.write(txtbuf, vsz);
|
|
stream.flush().get();
|
|
|
|
VERIFY_ARE_EQUAL(write.get(), vect.size());
|
|
VERIFY_IS_TRUE(write.is_done());
|
|
|
|
auto close = stream.close();
|
|
close.get();
|
|
|
|
VERIFY_IS_TRUE(close.is_done());
|
|
}
|
|
|
|
TEST(tell_bug)
|
|
{
|
|
auto count =
|
|
OPENSTR_W<uint8_t>(U("tell_bug.txt"), std::ios_base::out | std::ios_base::trunc).
|
|
then([=](concurrency::streams::ostream os) -> std::streamoff {
|
|
os.print("A");
|
|
auto val = os.tell();
|
|
os.close().get();
|
|
return val;
|
|
}).get();
|
|
|
|
VERIFY_ARE_EQUAL(std::streamoff(1), count);
|
|
}
|
|
|
|
TEST(iostream_container_buffer1)
|
|
{
|
|
concurrency::streams::container_buffer<std::vector<char>> buf;
|
|
|
|
auto os = buf.create_ostream();
|
|
os.write('a');
|
|
os.write('b');
|
|
os.close();
|
|
|
|
auto is = concurrency::streams::container_stream<std::vector<char>>::open_istream(std::move(buf.collection()));
|
|
VERIFY_ARE_EQUAL(is.read().get(), 'a');
|
|
VERIFY_ARE_EQUAL(is.read().get(), 'b');
|
|
}
|
|
|
|
TEST(iostream_container_buffer2)
|
|
{
|
|
concurrency::streams::container_buffer<std::vector<char>> buf;
|
|
|
|
{
|
|
auto os = buf.create_ostream();
|
|
os.write('a');
|
|
os.write('b');
|
|
os.close();
|
|
}
|
|
|
|
{
|
|
auto is = concurrency::streams::container_stream<std::vector<char>>::open_istream(std::move(buf.collection()));
|
|
|
|
is.read().then([&is](concurrency::streams::basic_ostream<char>::int_type c)
|
|
{
|
|
VERIFY_ARE_EQUAL(c, 'a');
|
|
return is.read();
|
|
}).then([&is](concurrency::streams::basic_ostream<char>::int_type c) -> pplx::task<void>
|
|
{
|
|
VERIFY_ARE_EQUAL(c, 'b');
|
|
return is.close();
|
|
}).wait();
|
|
}
|
|
}
|
|
|
|
TEST(extract_on_space)
|
|
{
|
|
const int number1 = 42;
|
|
const int number2 = 123;
|
|
|
|
auto open = OPENSTR_W<uint8_t>(U("SpaceWithNumber.txt"), std::ios::trunc);
|
|
auto stream = open.get();
|
|
VERIFY_IS_TRUE(open.is_done());
|
|
stream.print(" \r").wait();
|
|
stream.print(number1).wait();
|
|
stream.print("\n \t").wait();
|
|
stream.print(number2).wait();
|
|
stream.print(" \f \v ").wait();
|
|
stream.close().wait();
|
|
|
|
auto istream = OPENSTR_R<uint8_t>(U("SpaceWithNumber.txt")).get();
|
|
VERIFY_IS_TRUE(istream.can_seek());
|
|
VERIFY_ARE_EQUAL(number1, istream.extract<int>().get());
|
|
VERIFY_ARE_EQUAL(number2, istream.extract<long long>().get());
|
|
}
|
|
|
|
TEST(file_sequential_write)
|
|
{
|
|
auto open = OPENSTR_W<uint8_t>(U("WriteFileSequential.txt"), std::ios::trunc);
|
|
auto stream = open.get();
|
|
|
|
VERIFY_IS_TRUE(open.is_done());
|
|
|
|
std::vector<pplx::task<size_t>> v;
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
v.push_back(stream.print(i));
|
|
v.push_back(stream.print(' '));
|
|
}
|
|
pplx::when_all(v.begin(), v.end()).wait();
|
|
stream.close().wait();
|
|
auto istream = OPENSTR_R<uint8_t>(U("WriteFileSequential.txt")).get();
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
int int_read = istream.extract<int>().get();
|
|
if (int_read != i)
|
|
{
|
|
// This will fail
|
|
VERIFY_ARE_EQUAL(int_read, i);
|
|
|
|
// This return statment will prevent the test from hanging,
|
|
// cause if the numbers are merged there will be less than 100 numbers,
|
|
// and reading from the file will block
|
|
return;
|
|
}
|
|
istream.read().get();
|
|
}
|
|
}
|
|
|
|
TEST(implied_out_mode)
|
|
{
|
|
auto ostr = OPENSTR_W<char>(U("implied_out_mode.txt"), std::ios::ios_base::app).get();
|
|
|
|
std::string str = "abcd";
|
|
concurrency::streams::stringstreambuf block(str);
|
|
|
|
size_t s = ostr.write(block, str.size()).get();
|
|
|
|
VERIFY_ARE_EQUAL(s, str.size());
|
|
|
|
auto cls = ostr.close();
|
|
|
|
cls.get();
|
|
VERIFY_IS_TRUE(cls.is_done());
|
|
}
|
|
|
|
TEST(create_ostream_from_input_only)
|
|
{
|
|
container_buffer<std::string> sourceBuf("test data");
|
|
VERIFY_THROWS(sourceBuf.create_ostream(), std::runtime_error);
|
|
}
|
|
|
|
TEST(streambuf_close_with_exception_write)
|
|
{
|
|
container_buffer<std::string> sourceBuf;
|
|
sourceBuf.close(std::ios::out, std::make_exception_ptr(std::invalid_argument("custom exception"))).wait();
|
|
|
|
const size_t size = 4;
|
|
char targetBuf[size];
|
|
auto t1 = sourceBuf.putn_nocopy(targetBuf, size);
|
|
VERIFY_THROWS(t1.get(), std::invalid_argument);
|
|
}
|
|
|
|
TEST(stream_close_with_exception_write)
|
|
{
|
|
container_buffer<std::string> sourceBuf;
|
|
auto outStream = sourceBuf.create_ostream();
|
|
outStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))).wait();
|
|
|
|
container_buffer<std::string> targetBuf("test data");
|
|
auto t1 = outStream.write(targetBuf, 4);
|
|
VERIFY_THROWS(t1.get(), std::invalid_argument);
|
|
}
|
|
|
|
TEST(input_after_close)
|
|
{
|
|
container_buffer<std::string> sourceBuf;
|
|
auto outStream = sourceBuf.create_ostream();
|
|
outStream.close().wait();
|
|
|
|
container_buffer<std::string> targetBuf;
|
|
|
|
auto t1 = outStream.flush();
|
|
auto t2 = outStream.print('a');
|
|
auto t3 = outStream.print(std::string("abc"));
|
|
|
|
VERIFY_THROWS(t1.get(), std::runtime_error);
|
|
VERIFY_THROWS(t2.get(), std::runtime_error);
|
|
VERIFY_THROWS(t3.get(), std::runtime_error);
|
|
VERIFY_THROWS(outStream.seek(0), std::runtime_error);
|
|
VERIFY_THROWS(outStream.seek(0, std::ios::beg), std::runtime_error);
|
|
VERIFY_THROWS(outStream.tell(), std::runtime_error);
|
|
|
|
auto t4 = outStream.write('a');
|
|
auto t5 = outStream.write(targetBuf, 1);
|
|
VERIFY_THROWS(t4.get(), std::runtime_error);
|
|
VERIFY_THROWS(t5.get(), std::runtime_error);
|
|
}
|
|
|
|
TEST(write_emptybuffer_to_ostream)
|
|
{
|
|
auto ofs = OPENSTR_W<char>(U("file.txt")).get();
|
|
auto sbuf = concurrency::streams::producer_consumer_buffer<char>();
|
|
auto result = ofs.write(sbuf,0);
|
|
VERIFY_ARE_EQUAL(result.get(), 0);
|
|
}
|
|
|
|
TEST(write_stream_twice)
|
|
{
|
|
producer_consumer_buffer<uint8_t> buf1;
|
|
auto t1 = pplx::create_task([&]{
|
|
buf1.alloc(8);
|
|
buf1.alloc(9);
|
|
});
|
|
VERIFY_THROWS(t1.get(), std::logic_error);
|
|
|
|
std::string strData("test string to write\n");
|
|
container_buffer<std::string> buf2(std::move(strData));
|
|
auto t2 = pplx::create_task([&]{
|
|
buf2.commit(8);
|
|
buf2.alloc(9);
|
|
});
|
|
VERIFY_THROWS(t2.get(), std::logic_error);
|
|
|
|
rawptr_buffer<std::string> buf3;
|
|
auto t3 = pplx::create_task([&]{
|
|
buf3.commit(8);
|
|
buf3.commit(9);
|
|
});
|
|
VERIFY_THROWS(t3.get(), std::logic_error);
|
|
}
|
|
|
|
} // SUITE(ostream_tests)
|
|
|
|
}}}
|
|
|