1515#include " google/cloud/spanner/client.h"
1616#include " google/cloud/spanner/database.h"
1717#include " google/cloud/spanner/database_admin_client.h"
18+ #include " google/cloud/spanner/internal/time.h"
1819#include " google/cloud/spanner/mutations.h"
1920#include " google/cloud/spanner/testing/database_environment.h"
2021#include " google/cloud/internal/getenv.h"
@@ -28,6 +29,36 @@ namespace spanner {
2829inline namespace SPANNER_CLIENT_NS {
2930namespace {
3031
32+ using ::testing::UnorderedElementsAreArray;
33+
34+ // A helper function used in the test fixtures below. This function writes the
35+ // given data to the DataTypes table, then it reads all the data back and
36+ // returns it to the caller.
37+ template <typename T>
38+ StatusOr<T> WriteReadData (Client& client, T const & data,
39+ std::string const & column) {
40+ auto commit_result = client.Commit (
41+ [&data, &column](Transaction const &) -> StatusOr<Mutations> {
42+ Mutations mutations;
43+ int id = 0 ;
44+ for (auto const & x : data) {
45+ mutations.push_back (MakeInsertMutation (
46+ " DataTypes" , {" Id" , column}, " Id-" + std::to_string (id++), x));
47+ }
48+ return mutations;
49+ });
50+ if (!commit_result) return commit_result.status ();
51+
52+ T actual;
53+ auto rows = client.Read (" DataTypes" , KeySet::All (), {column});
54+ using RowType = std::tuple<typename T::value_type>;
55+ for (auto const & row : StreamOf<RowType>(rows)) {
56+ if (!row) return row.status ();
57+ actual.push_back (std::get<0 >(*row));
58+ }
59+ return actual;
60+ }
61+
3162class DataTypeIntegrationTest : public ::testing::Test {
3263 public:
3364 static void SetUpTestSuite () {
@@ -38,7 +69,6 @@ class DataTypeIntegrationTest : public ::testing::Test {
3869 void SetUp () override {
3970 auto commit_result = client_->Commit ([](Transaction const &) {
4071 return Mutations{
41- MakeDeleteMutation (" Singers" , KeySet::All ()),
4272 MakeDeleteMutation (" DataTypes" , KeySet::All ()),
4373 };
4474 });
@@ -53,37 +83,129 @@ class DataTypeIntegrationTest : public ::testing::Test {
5383
5484std::unique_ptr<Client> DataTypeIntegrationTest::client_;
5585
56- TEST_F (DataTypeIntegrationTest, ReadWriteDate) {
57- auto & client = *client_;
58- using RowType = std::tuple<std::string, Date, std::string>;
59- RowType read_back;
60- auto commit_result = client_->Commit (
61- [&client, &read_back](Transaction const & txn) -> StatusOr<Mutations> {
62- auto result = client.ExecuteDml (
63- txn,
64- SqlStatement (
65- " INSERT INTO DataTypes (Id, DateValue, StringValue) "
66- " VALUES(@id, @date, @event)" ,
67- {{" id" , Value (" ReadWriteDate-1" )},
68- {" date" , Value (Date (161 , 3 , 8 ))},
69- {" event" , Value (" Marcus Aurelius ascends to the throne" )}}));
70- if (!result) return std::move (result).status ();
71-
72- auto reader = client.ExecuteQuery (
73- txn, SqlStatement (" SELECT Id, DateValue, StringValue FROM DataTypes"
74- " WHERE Id = @id" ,
75- {{" id" , Value (" ReadWriteDate-1" )}}));
76-
77- auto row = GetSingularRow (StreamOf<RowType>(reader));
78- if (!row) return std::move (row).status ();
79- read_back = *std::move (row);
80- return Mutations{};
81- });
86+ TEST_F (DataTypeIntegrationTest, WriteReadBool) {
87+ std::vector<bool > const data = {true , false };
88+ auto result = WriteReadData (*client_, data, " BoolValue" );
89+ ASSERT_STATUS_OK (result);
90+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
91+ }
92+
93+ TEST_F (DataTypeIntegrationTest, WriteReadInt64) {
94+ std::vector<std::int64_t > const data = {
95+ std::numeric_limits<std::int64_t >::min (), -123 , -42 , -1 , 0 , 1 , 42 , 123 ,
96+ std::numeric_limits<std::int64_t >::max (),
97+ };
98+ auto result = WriteReadData (*client_, data, " Int64Value" );
99+ ASSERT_STATUS_OK (result);
100+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
101+ }
102+
103+ TEST_F (DataTypeIntegrationTest, WriteReadFloat64) {
104+ std::vector<double > const data = {
105+ -std::numeric_limits<double >::infinity (),
106+ std::numeric_limits<double >::lowest (),
107+ std::numeric_limits<double >::min (),
108+ -123.456 ,
109+ -123 ,
110+ -42.42 ,
111+ -42 ,
112+ -1.5 ,
113+ -1 ,
114+ -0.5 ,
115+ 0 ,
116+ 0.5 ,
117+ 1 ,
118+ 1.5 ,
119+ 42 ,
120+ 42.42 ,
121+ 123 ,
122+ 123.456 ,
123+ std::numeric_limits<double >::max (),
124+ std::numeric_limits<double >::infinity (),
125+ };
126+ auto result = WriteReadData (*client_, data, " Float64Value" );
127+ ASSERT_STATUS_OK (result);
128+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
129+ }
130+
131+ TEST_F (DataTypeIntegrationTest, WriteReadFloat64NaN) {
132+ // Since NaN is not equal to anything, including itself, we need to handle
133+ // NaN separately from other Float64 values.
134+ std::vector<double > const data = {
135+ std::numeric_limits<double >::quiet_NaN (),
136+ };
137+ auto result = WriteReadData (*client_, data, " Float64Value" );
138+ ASSERT_STATUS_OK (result);
139+ EXPECT_EQ (1 , result->size ());
140+ EXPECT_TRUE (std::isnan (result->front ()));
141+ }
142+
143+ TEST_F (DataTypeIntegrationTest, WriteReadString) {
144+ std::vector<std::string> const data = {
145+ " " ,
146+ " a" ,
147+ " Hello World" ,
148+ " 123456789012345678901234567890" ,
149+ std::string (1024 , ' x' ),
150+ };
151+ auto result = WriteReadData (*client_, data, " StringValue" );
152+ ASSERT_STATUS_OK (result);
153+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
154+ }
155+
156+ TEST_F (DataTypeIntegrationTest, WriteReadBytes) {
157+ // Makes a blob containing unprintable characters.
158+ std::string blob;
159+ for (char c = std::numeric_limits<char >::min ();
160+ c != std::numeric_limits<char >::max (); ++c) {
161+ blob.push_back (c);
162+ }
163+ std::vector<Bytes> const data = {
164+ Bytes (" " ),
165+ Bytes (" a" ),
166+ Bytes (" Hello World" ),
167+ Bytes (" 123456789012345678901234567890" ),
168+ Bytes (blob),
169+ };
170+ auto result = WriteReadData (*client_, data, " BytesValue" );
171+ ASSERT_STATUS_OK (result);
172+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
173+ }
174+
175+ TEST_F (DataTypeIntegrationTest, WriteReadTimestamp) {
176+ // TODO(#1098): `Timestamp` cannot represent these extreme values.
177+ // auto min = internal::TimestampFromString("0001-01-01T00:00:00Z");
178+ // auto max = internal::TimestampFromString("9999-12-31T23:59:59.999999999Z");
179+
180+ // ASSERT_STATUS_OK(min);
181+ // ASSERT_STATUS_OK(max);
182+
183+ std::vector<Timestamp> const data = {
184+ // *min, // TODO(#1098)
185+ Timestamp (std::chrono::seconds (-1 )),
186+ Timestamp (std::chrono::nanoseconds (-1 )),
187+ Timestamp (std::chrono::seconds (0 )),
188+ Timestamp (std::chrono::nanoseconds (1 )),
189+ Timestamp (std::chrono::seconds (1 )),
190+ Timestamp (std::chrono::system_clock::now ()),
191+ // *max, // TODO(#1098)
192+ };
193+ auto result = WriteReadData (*client_, data, " TimestampValue" );
194+ ASSERT_STATUS_OK (result);
195+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
196+ }
82197
83- ASSERT_TRUE (commit_result.ok ());
84- EXPECT_EQ (" ReadWriteDate-1" , std::get<0 >(read_back));
85- EXPECT_EQ (Date (161 , 3 , 8 ), std::get<1 >(read_back));
86- EXPECT_EQ (" Marcus Aurelius ascends to the throne" , std::get<2 >(read_back));
198+ TEST_F (DataTypeIntegrationTest, WriteReadDate) {
199+ std::vector<Date> const data = {
200+ Date (1 , 1 , 1 ), //
201+ Date (161 , 3 , 8 ), //
202+ Date (), //
203+ Date (2019 , 11 , 21 ), //
204+ Date (9999 , 12 , 31 ), //
205+ };
206+ auto result = WriteReadData (*client_, data, " DateValue" );
207+ ASSERT_STATUS_OK (result);
208+ EXPECT_THAT (*result, UnorderedElementsAreArray (data));
87209}
88210
89211} // namespace
0 commit comments