1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 #include "tink/internal/test_random_access_stream.h"
17
18 #include <memory>
19 #include <string>
20 #include <utility>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/status/status.h"
25 #include "tink/subtle/random.h"
26 #include "tink/util/buffer.h"
27 #include "tink/util/status.h"
28 #include "tink/util/test_matchers.h"
29
30 namespace crypto {
31 namespace tink {
32 namespace internal {
33 namespace {
34
35 using ::crypto::tink::test::StatusIs;
36
TEST(TestRandomAccessStreamTest,ReadAllSucceeds)37 TEST(TestRandomAccessStreamTest, ReadAllSucceeds) {
38 const int buffer_size = 4 * 1024;
39 const int stream_size = 100 * 1024;
40 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
41 auto rand_access_stream =
42 std::make_unique<TestRandomAccessStream>(stream_content);
43 auto buffer = *std::move(util::Buffer::New(buffer_size));
44 util::Status pread_status = util::OkStatus();
45 std::string result;
46 do {
47 pread_status =
48 rand_access_stream->PRead(result.size(), buffer_size, buffer.get());
49 result.append(buffer->get_mem_block(), buffer->size());
50 } while (pread_status.ok());
51 EXPECT_THAT(pread_status, StatusIs(absl::StatusCode::kOutOfRange));
52 EXPECT_EQ(result, stream_content);
53 }
54
TEST(TestRandomAccessStreamTest,PreadAllInOnePread)55 TEST(TestRandomAccessStreamTest, PreadAllInOnePread) {
56 const int stream_size = 8 * 1024;
57 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
58 auto rand_access_stream =
59 std::make_unique<TestRandomAccessStream>(stream_content);
60 auto buffer = *std::move(util::Buffer::New(stream_size));
61 ASSERT_THAT(
62 rand_access_stream->PRead(/*position=*/0, stream_size, buffer.get()),
63 StatusIs(absl::StatusCode::kOutOfRange));
64 EXPECT_EQ(std::string(buffer->get_mem_block(), buffer->size()),
65 stream_content);
66 }
67
TEST(TestRandomAccessStreamTest,PreadCountLargerThanBufferFails)68 TEST(TestRandomAccessStreamTest, PreadCountLargerThanBufferFails) {
69 const int buffer_size = 4 * 1024;
70 const int stream_size = 100 * 1024;
71 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
72 auto rand_access_stream =
73 std::make_unique<TestRandomAccessStream>(stream_content);
74 auto buffer = *std::move(util::Buffer::New(buffer_size));
75 EXPECT_THAT(
76 rand_access_stream->PRead(/*position=*/0, buffer_size + 1, buffer.get()),
77 StatusIs(absl::StatusCode::kInvalidArgument));
78 }
79
TEST(TestRandomAccessStreamTest,InvalidPosition)80 TEST(TestRandomAccessStreamTest, InvalidPosition) {
81 const int buffer_size = 4 * 1024;
82 const int stream_size = 100 * 1024;
83 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
84 auto rand_access_stream =
85 std::make_unique<TestRandomAccessStream>(stream_content);
86 auto buffer = *std::move(util::Buffer::New(buffer_size));
87 EXPECT_THAT(rand_access_stream->PRead(-1, buffer_size, buffer.get()),
88 StatusIs(absl::StatusCode::kInvalidArgument));
89 }
90
TEST(TestRandomAccessStreamTest,PreadWithNullBufferFails)91 TEST(TestRandomAccessStreamTest, PreadWithNullBufferFails) {
92 const int stream_size = 100 * 1024;
93 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
94 auto rand_access_stream =
95 std::make_unique<TestRandomAccessStream>(stream_content);
96 EXPECT_THAT(rand_access_stream->PRead(/*position=*/0, stream_size,
97 /*dest_buffer=*/nullptr),
98 StatusIs(absl::StatusCode::kInvalidArgument));
99 }
100
TEST(TestRandomAccessStreamTest,PreadWithEmptyStreamEof)101 TEST(TestRandomAccessStreamTest, PreadWithEmptyStreamEof) {
102 const int buffer_size = 4 * 1024;
103 std::string stream_content; // Empty string.
104 auto rand_access_stream =
105 std::make_unique<TestRandomAccessStream>(stream_content);
106 auto buffer = *std::move(util::Buffer::New(buffer_size));
107 EXPECT_THAT(
108 rand_access_stream->PRead(/*position=*/0, buffer_size, buffer.get()),
109 StatusIs(absl::StatusCode::kOutOfRange));
110 }
111
112 // Pread of the last partial block populates the buffer with the remaining
113 // bytes and returns an EOF status.
TEST(TestRandomAccessStreamTest,PreadTheLastPartialBlockReturnsEof)114 TEST(TestRandomAccessStreamTest, PreadTheLastPartialBlockReturnsEof) {
115 const int buffer_size = 4 * 1024;
116 const int stream_size = 100 * 1024;
117 std::string stream_content = subtle::Random::GetRandomBytes(stream_size);
118 auto rand_access_stream =
119 std::make_unique<TestRandomAccessStream>(stream_content);
120 auto buffer = *std::move(util::Buffer::New(buffer_size));
121 // Read at a postion so that only buffer_size - 1 bytes are left.
122 EXPECT_THAT(rand_access_stream->PRead(stream_size - buffer_size + 1,
123 buffer_size, buffer.get()),
124 StatusIs(absl::StatusCode::kOutOfRange));
125 EXPECT_EQ(buffer->size(), buffer_size - 1);
126 EXPECT_EQ(std::string(buffer->get_mem_block(), buffer->size()),
127 stream_content.substr(stream_size - buffer_size + 1));
128 }
129
TEST(TestRandomAccessStreamTest,ReadAllFromRandomAccessStreamSucceeds)130 TEST(TestRandomAccessStreamTest, ReadAllFromRandomAccessStreamSucceeds) {
131 std::string content_to_read = subtle::Random::GetRandomBytes(4 * 1024);
132 auto test_random_access_stream =
133 std::make_unique<TestRandomAccessStream>(content_to_read);
134 std::string read_content;
135 EXPECT_THAT(ReadAllFromRandomAccessStream(test_random_access_stream.get(),
136 read_content,
137 /*chunk_size=*/128),
138 StatusIs(absl::StatusCode::kOutOfRange));
139 EXPECT_EQ(content_to_read, read_content);
140 }
141
TEST(TestRandomAccessStreamTest,ReadAllFromRandomAccessStreamFailsWhenChunkIsLessThanOne)142 TEST(TestRandomAccessStreamTest,
143 ReadAllFromRandomAccessStreamFailsWhenChunkIsLessThanOne) {
144 std::string content_to_read = subtle::Random::GetRandomBytes(4 * 1024);
145 auto test_random_access_stream =
146 std::make_unique<TestRandomAccessStream>(content_to_read);
147 std::string read_content;
148 EXPECT_THAT(ReadAllFromRandomAccessStream(test_random_access_stream.get(),
149 read_content,
150 /*chunk_size=*/0),
151 StatusIs(absl::StatusCode::kInvalidArgument));
152 EXPECT_THAT(ReadAllFromRandomAccessStream(test_random_access_stream.get(),
153 read_content,
154 /*chunk_size=*/-10),
155 StatusIs(absl::StatusCode::kInvalidArgument));
156 }
157
158 } // namespace
159 } // namespace internal
160 } // namespace tink
161 } // namespace crypto
162