Skip to content

Commit bb2fd5e

Browse files
authored
Merge pull request #3 from awslabs/SetFailureBitIfFileOpenFails
Make sure that failbit is set after unsuccessful is3stream opens
2 parents f293bf7 + 8b24743 commit bb2fd5e

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

include/awslabs/enhanced/is3stream.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <awslabs/enhanced/s3buf.h>
77
#include <string>
8+
#include <string_view>
89
#include <istream>
910

1011
namespace AwsLabs::Enhanced {
@@ -13,6 +14,16 @@ class is3stream : public std::istream {
1314
std::string _region;
1415
std::string _bucket_name;
1516
std::string _object_name;
17+
protected:
18+
/**
19+
* Opens the current region/bucket/object and set the iostate
20+
*/
21+
void open(std::ios_base::openmode mode = std::ios_base::in) {
22+
if(_s3b->open(_region, _bucket_name, _object_name, mode))
23+
std::ios::setstate(goodbit);
24+
else
25+
std::ios::setstate(failbit);
26+
}
1627
public:
1728
/**
1829
* Default constructor for a is3stream not associated to an S3 object
@@ -41,7 +52,8 @@ class is3stream : public std::istream {
4152
* @return
4253
*/
4354
is3stream &operator=(is3stream &&is3s) {
44-
_s3b->close();
55+
if(is_open())
56+
_s3b->close();
4557
_region = is3s._region;
4658
_bucket_name = is3s._bucket_name;
4759
_object_name = is3s._object_name;
@@ -63,7 +75,7 @@ class is3stream : public std::istream {
6375
_region = region;
6476
_bucket_name = bucket_name;
6577
_object_name = object_name;
66-
_s3b->open(_region, _bucket_name, _object_name, std::ios_base::in);
78+
open();
6779
}
6880

6981
/**
@@ -87,7 +99,7 @@ class is3stream : public std::istream {
8799
*/
88100
void open(const std::string &object_name) {
89101
_object_name = object_name;
90-
_s3b->open(_region, _bucket_name, _object_name, std::ios_base::in);
102+
open();
91103
}
92104
/**
93105
* Opens object_name in previously set region and bucket to read content from it.
@@ -99,7 +111,7 @@ class is3stream : public std::istream {
99111
_region = region;
100112
_bucket_name = bucket_name;
101113
_object_name = object_name;
102-
_s3b->open(_region, _bucket_name, _object_name, std::ios_base::in);
114+
open();
103115
}
104116
/**
105117
* Returns whether the is3stream is currently associated to an S3 object.
@@ -137,7 +149,12 @@ class is3stream : public std::istream {
137149
}
138150

139151
virtual ~is3stream() {
140-
delete _s3b;
152+
try {
153+
delete _s3b;
154+
} catch(...) {
155+
// Don't throw from destructors
156+
// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-never-fail
157+
}
141158
}
142159
};
143160

test/test_is3stream.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
#include "gtest/gtest.h"
99
#include "test_helpers.h"
10-
1110
namespace {
1211
class is3sIntegrationTest : public ::testing::Test {
1312
protected:
@@ -85,4 +84,19 @@ TEST_F(is3sIntegrationTest, CanReadFirstWordFromIs3s) {
8584
is3s >> result;
8685
ASSERT_FALSE(result.empty()) << "Second word is also extracted";
8786
}
87+
88+
TEST_F(is3sIntegrationTest, DetectS3FailureInIs3sConstructor) {
89+
// "foo" exists but we do not have permission to read
90+
AwsLabs::Enhanced::is3stream is3s(infra.m_region, "foo", infra.m_object_name);
91+
// Vary tests between checking for failure and exceptions for greater robustness
92+
ASSERT_THROW(is3s.exceptions(std::ios_base::failbit | std::ios_base::badbit), std::ios_base::failure);
93+
}
94+
95+
TEST_F(is3sIntegrationTest, DetectS3FailureInIs3sOpen) {
96+
AwsLabs::Enhanced::is3stream is3s;
97+
// "foo" exists but we do not have permission to read
98+
is3s.open(infra.m_region, "foo", infra.m_object_name);
99+
ASSERT_TRUE(is3s.fail() && !is3s.bad());
100+
}
101+
88102
}

0 commit comments

Comments
 (0)