TEST_FIXTURE(blob_service_test_base_with_objects_to_delete, list_containers)
    {
        auto prefix = get_random_container_name();

        create_containers(prefix, 1);

        auto listing = list_all_containers(utility::string_t(), azure::storage::container_listing_details::all, 5001, azure::storage::blob_request_options());
        
        check_container_list(listing, prefix, false);
    }
    TEST_FIXTURE(blob_service_test_base_with_objects_to_delete, list_blobs_from_client_root)
    {
        auto root_container = m_client.get_root_container_reference();
        root_container.create_if_not_exists();

        auto prefix = get_random_container_name();

        create_blobs(root_container, prefix, 1);

        auto listing = list_all_blobs_from_client(prefix, azure::storage::blob_listing_details::none, 1, azure::storage::blob_request_options());
        
        check_blob_list(listing);
    }
    TEST_FIXTURE(blob_service_test_base, get_container_reference)
    {
        utility::string_t container_name = get_random_container_name();
        azure::storage::cloud_blob_container container = m_client.get_container_reference(container_name);

        CHECK(!container.service_client().base_uri().primary_uri().is_empty());
        CHECK(container.service_client().credentials().is_shared_key());
        CHECK(container.name() == container_name);
        CHECK(!container.uri().primary_uri().is_empty());
        CHECK(container.metadata().empty());
        CHECK(container.properties().etag().empty());
        CHECK(!container.properties().last_modified().is_initialized());
        CHECK(container.properties().lease_status() == azure::storage::lease_status::unspecified);
        CHECK(container.properties().lease_state() == azure::storage::lease_state::unspecified);
        CHECK(container.properties().lease_duration() == azure::storage::lease_duration::unspecified);
        CHECK(container.is_valid());
    }
    TEST_FIXTURE(blob_service_test_base_with_objects_to_delete, list_containers_with_continuation_token)
    {
        auto prefix = get_random_container_name();
        create_containers(prefix, 10);

        std::vector<azure::storage::cloud_blob_container> listing;
        azure::storage::continuation_token token;
        azure::storage::blob_request_options options;
        do{
            auto results = m_client.list_containers_segmented(prefix, azure::storage::container_listing_details::all, 3, token, options, m_context);
            CHECK(results.results().size() <= 3);

            std::copy(results.results().begin(), results.results().end(), std::back_inserter(listing));
            token = results.continuation_token();
        } while (!token.empty());

        check_container_list(listing, prefix, true);
    }
    TEST_FIXTURE(blob_test_base, list_blobs_from_client)
    {
        std::vector<azure::storage::cloud_blob> blobs;
        auto prefix = get_random_container_name();

        std::vector<azure::storage::cloud_blob> blobs2;
        auto prefix2 = get_random_container_name();

        for (int i = 0; i < 3; i++)
        {
            auto index = utility::conversions::print_string(i);
            auto blob = m_container.get_block_blob_reference(prefix + index);
            blob.upload_text(U("test"), azure::storage::access_condition(), azure::storage::blob_request_options(), m_context);
            blobs.push_back(blob);
        }

        for (int i = 0; i < 2; i++)
        {
            auto index = utility::conversions::print_string(i);
            auto blob = m_container.get_block_blob_reference(prefix2 + index);
            blob.upload_text(U("test2"), azure::storage::access_condition(), azure::storage::blob_request_options(), m_context);
            blobs2.push_back(blob);
        }

        std::vector<azure::storage::cloud_blob> all_blobs(blobs);
        all_blobs.insert(all_blobs.end(), blobs2.begin(), blobs2.end());

        auto listing = list_all_blobs_from_client(m_container.name(), azure::storage::blob_listing_details::none, 0, azure::storage::blob_request_options());
        CHECK(listing.empty());

        listing = list_all_blobs_from_client(m_container.name() + U("/"), azure::storage::blob_listing_details::none, 0, azure::storage::blob_request_options());
        CHECK_EQUAL(5U, listing.size());
        for (auto listing_iter = listing.begin(); listing_iter != listing.end(); ++listing_iter)
        {
            for (auto iter = all_blobs.begin(); iter != all_blobs.end(); ++iter)
            {
                if (iter->name() == listing_iter->name())
                {
                    all_blobs.erase(iter);
                    break;
                }
            }
        }

        CHECK(all_blobs.empty());

        std::vector<azure::storage::cloud_blob> blobs_copy(blobs);

        listing = list_all_blobs_from_client(m_container.name() + U("/") + prefix, azure::storage::blob_listing_details::none, 0, azure::storage::blob_request_options());
        CHECK_EQUAL(3U, listing.size());
        for (auto listing_iter = listing.begin(); listing_iter != listing.end(); ++listing_iter)
        {
            for (auto iter = blobs_copy.begin(); iter != blobs_copy.end(); ++iter)
            {
                if (iter->name() == listing_iter->name())
                {
                    blobs_copy.erase(iter);
                    break;
                }
            }
        }

        CHECK(blobs_copy.empty());
    }
    TEST_FIXTURE(append_blob_test_base, append_blob_append)
    {
        const size_t file_buffer_size = 24 * 1024 * 1024 + 6;
        std::vector<uint8_t> file_buffer;
        file_buffer.resize(file_buffer_size);

        azure::storage::blob_request_options options;
        options.set_use_transactional_md5(false);

        utility::string_t md5_header;
        m_context.set_sending_request([&md5_header](web::http::http_request& request, azure::storage::operation_context)
        {
            if (!request.headers().match(web::http::header_names::content_md5, md5_header))
            {
                md5_header.clear();
            }
        });

        m_blob.create_or_replace(azure::storage::access_condition(), options, m_context);

        int block_count = 0;

        // append stream (4M, 4M)
        const size_t buffer_offsets1[2] = { 0, 4 * 1024 * 1024};
        for (uint16_t i = 0; i < 2; ++i)
        {
            std::vector<uint8_t> buffer;
            buffer.resize(4 * 1024 * 1024);
            fill_buffer_and_get_md5(buffer);
            std::copy(buffer.begin(), buffer.end(), file_buffer.begin() + buffer_offsets1[i]);

            auto stream = concurrency::streams::bytestream::open_istream(buffer);
            azure::storage::access_condition condition = azure::storage::access_condition::generate_if_append_position_equal_condition(buffer_offsets1[i]);
            m_blob.append_from_stream(stream, condition, options, m_context);
            CHECK_UTF8_EQUAL(utility::string_t(), md5_header);

            block_count++;
            CHECK_EQUAL(block_count, m_blob.properties().append_blob_committed_block_count());
        }

        // append stream with length (2M, 2M, 2M)
        const size_t buffer_offsets2[3] = { 8 * 1024 * 1024,  10 * 1024 * 1024, 12 * 1024 * 1024 };
        for (uint16_t i = 0; i < 3; ++i)
        {
            std::vector<uint8_t> buffer;
            buffer.resize(4 * 1024 * 1024);
            fill_buffer_and_get_md5(buffer);
            std::copy(buffer.begin(), buffer.begin() + 2 * 1024 * 1024, file_buffer.begin() + buffer_offsets2[i]);

            auto stream = concurrency::streams::bytestream::open_istream(buffer);
            m_blob.append_from_stream(stream, 2 * 1024 * 1024, azure::storage::access_condition(), options, m_context);
            CHECK_UTF8_EQUAL(utility::string_t(), md5_header);

            block_count++;
            CHECK_EQUAL(block_count, m_blob.properties().append_blob_committed_block_count());
        }

        // append file (5M, 5M)
        const size_t buffer_offsets3[2] = { 14 * 1024 * 1024, 19 * 1024 * 1024 };
        for (uint16_t i = 0; i < 2; ++i)
        {
            std::vector<uint8_t> buffer;
            buffer.resize(5 * 1024 * 1024);
            fill_buffer_and_get_md5(buffer);
            std::copy(buffer.begin(), buffer.end(), file_buffer.begin() + buffer_offsets3[i]);

            // create a temporary test file
            utility::string_t tmp_file_path = get_random_container_name(8);
            auto stream = concurrency::streams::file_stream<uint8_t>::open_ostream(tmp_file_path).get();
            stream.streambuf().putn_nocopy(buffer.data(), buffer.size()).wait();
            stream.close().wait();

            // append from file
            m_blob.append_from_file(tmp_file_path, azure::storage::access_condition(), options, m_context);

            // remote the temporary test file
            std::remove(utility::conversions::to_utf8string(tmp_file_path).c_str());

            block_count  += 2;
            CHECK_EQUAL(block_count, m_blob.properties().append_blob_committed_block_count());
        }

        // append text (1, 5)
        const size_t buffer_offsets4[2] = { 24 * 1024 * 1024, 24 * 1024 * 1024 + 1};
        {
            utility::string_t text1 = U("1");
            std::string text1_copy = utility::conversions::to_utf8string(text1);
            std::copy(text1_copy.begin(), text1_copy.end(), file_buffer.begin() + buffer_offsets4[0]);
            m_blob.append_text(text1);
            block_count++;
            CHECK_EQUAL(block_count, m_blob.properties().append_blob_committed_block_count());

            utility::string_t text2 = U("test2");
            std::string text2_copy = utility::conversions::to_utf8string(text2);
            std::copy(text2_copy.begin(), text2_copy.end(), file_buffer.begin() + buffer_offsets4[1]);
            m_blob.append_text(text2);
            block_count++;
            CHECK_EQUAL(block_count, m_blob.properties().append_blob_committed_block_count());
        }

        // download the blob
        concurrency::streams::container_buffer<std::vector<uint8_t>> downloaded_blob;
        m_blob.download_to_stream(downloaded_blob.create_ostream(), azure::storage::access_condition(), options, m_context);

        CHECK_ARRAY_EQUAL(file_buffer, downloaded_blob.collection(), (int)file_buffer.size());

        m_blob.delete_blob();

        m_context.set_sending_request(std::function<void(web::http::http_request &, azure::storage::operation_context)>());
    }