/*** * ==++== * * 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 pplx::task> 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 pplx::task> 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(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(U("BasicTest2.txt")); auto cls = open.then( [](pplx::task op) -> pplx::task { 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(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(U("WriteBufferStrTest1.txt")); auto stream = open.get(); VERIFY_IS_TRUE(open.is_done()); std::vector vect; for (char ch = 'a'; ch <= 'z'; ch++) { vect.push_back(ch); } size_t vsz = vect.size(); concurrency::streams::container_stream>::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(U("WriteBufferAndSyncStrTest1.txt")); auto stream = open.get(); VERIFY_IS_TRUE(open.is_done()); std::vector vect; for (char ch = 'a'; ch <= 'z'; ch++) { vect.push_back(ch); } size_t vsz = vect.size(); concurrency::streams::rawptr_buffer txtbuf(reinterpret_cast(&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(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> buf; auto os = buf.create_ostream(); os.write('a'); os.write('b'); os.close(); auto is = concurrency::streams::container_stream>::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> buf; { auto os = buf.create_ostream(); os.write('a'); os.write('b'); os.close(); } { auto is = concurrency::streams::container_stream>::open_istream(std::move(buf.collection())); is.read().then([&is](concurrency::streams::basic_ostream::int_type c) { VERIFY_ARE_EQUAL(c, 'a'); return is.read(); }).then([&is](concurrency::streams::basic_ostream::int_type c) -> pplx::task { 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(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(U("SpaceWithNumber.txt")).get(); VERIFY_IS_TRUE(istream.can_seek()); VERIFY_ARE_EQUAL(number1, istream.extract().get()); VERIFY_ARE_EQUAL(number2, istream.extract().get()); } TEST(file_sequential_write) { auto open = OPENSTR_W(U("WriteFileSequential.txt"), std::ios::trunc); auto stream = open.get(); VERIFY_IS_TRUE(open.is_done()); std::vector> 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(U("WriteFileSequential.txt")).get(); for (int i = 0; i < 100; i++) { int int_read = istream.extract().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(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 sourceBuf("test data"); VERIFY_THROWS(sourceBuf.create_ostream(), std::runtime_error); } TEST(streambuf_close_with_exception_write) { container_buffer 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 sourceBuf; auto outStream = sourceBuf.create_ostream(); outStream.close(std::make_exception_ptr(std::invalid_argument("custom exception"))).wait(); container_buffer targetBuf("test data"); auto t1 = outStream.write(targetBuf, 4); VERIFY_THROWS(t1.get(), std::invalid_argument); } TEST(input_after_close) { container_buffer sourceBuf; auto outStream = sourceBuf.create_ostream(); outStream.close().wait(); container_buffer 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(U("file.txt")).get(); auto sbuf = concurrency::streams::producer_consumer_buffer(); auto result = ofs.write(sbuf,0); VERIFY_ARE_EQUAL(result.get(), 0); } TEST(write_stream_twice) { producer_consumer_buffer 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 buf2(std::move(strData)); auto t2 = pplx::create_task([&]{ buf2.commit(8); buf2.alloc(9); }); VERIFY_THROWS(t2.get(), std::logic_error); rawptr_buffer buf3; auto t3 = pplx::create_task([&]{ buf3.commit(8); buf3.commit(9); }); VERIFY_THROWS(t3.get(), std::logic_error); } } // SUITE(ostream_tests) }}}