1 /**
2  * @file   unit-cppapi-config.cc
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * Util Tests for C++ API.
31  */
32 
33 #include <thread>
34 
35 #include "catch.hpp"
36 #include "tiledb/sm/c_api/tiledb_serialization.h"
37 #include "tiledb/sm/cpp_api/tiledb"
38 
setenv_local(const char * __name,const char * __value)39 int setenv_local(const char* __name, const char* __value) {
40 #ifdef _WIN32
41   return _putenv_s(__name, __value);
42 #else
43   return ::setenv(__name, __value, 1);
44 #endif
45 }
46 
47 TEST_CASE("C++ API: Config", "[cppapi][config]") {
48   tiledb::Config config;
49   config["foo"] = "bar";
50   std::string result1 = config["foo"];
51   CHECK(result1 == "bar");
52 
__anonf5ec81500102() 53   auto readInvalidKey = [&config]() { std::string result2 = config["bar"]; };
54   REQUIRE_THROWS_AS(readInvalidKey(), tiledb::TileDBError);
55 }
56 
57 TEST_CASE("C++ API: Config iterator", "[cppapi][cppapi-config]") {
58   tiledb::Config config;
59   std::vector<std::string> names;
60   for (auto it = config.begin("vfs"), ite = config.end(); it != ite; ++it) {
61     names.push_back(it->first);
62   }
63   // Check number of VFS params in default config object.
64   CHECK(names.size() == 58);
65 }
66 
67 TEST_CASE("C++ API: Config Environment Variables", "[cppapi][cppapi-config]") {
68   tiledb::Config config;
__anonf5ec81500202() 69   auto readInvalidKey = [&config]() { std::string result1 = config["foo"]; };
70   REQUIRE_THROWS_AS(readInvalidKey(), tiledb::TileDBError);
71 
72   setenv_local("TILEDB_FOO", "bar");
73   std::string result1 = config["foo"];
74   CHECK(result1 == "bar");
75 
76   setenv_local("TILEDB_FOO", "bar2");
77   std::string result2 = config["foo"];
78   CHECK(result2 == "bar2");
79 
80   config["config.env_var_prefix"] = "TILEDB_TEST_";
__anonf5ec81500302() 81   auto readInvalidKey2 = [&config]() { std::string result2 = config["foo"]; };
82   REQUIRE_THROWS_AS(readInvalidKey2(), tiledb::TileDBError);
83 
84   setenv_local("TILEDB_TEST_FOO", "bar3");
85   std::string result3 = config["foo"];
86   CHECK(result3 == "bar3");
87 }
88 
89 TEST_CASE(
90     "C++ API: Config Environment Variables Default Override",
91     "[cppapi][cppapi-config]") {
92   tiledb::Config config;
93   const std::string key = "sm.io_concurrency_level";
94 
95   unsigned int threads = std::thread::hardware_concurrency();
96   const std::string result1 = config[key];
97   CHECK(result1 == std::to_string(threads));
98 
99   const std::string value2 = std::to_string(threads + 1);
100   setenv_local("TILEDB_SM_IO_CONCURRENCY_LEVEL", value2.c_str());
101   const std::string result2 = config[key];
102   CHECK(result2 == value2);
103 
104   // Check iterator
105   for (auto& c : config) {
106     if (c.first == key) {
107       CHECK(c.second == value2);
108     }
109   }
110 
111   const std::string value3 = std::to_string(threads + 2);
112   config[key] = value3;
113   const std::string result3 = config[key];
114   CHECK(result3 == value3);
115 }
116 
117 TEST_CASE("C++ API: Config Equality", "[cppapi][cppapi-config]") {
118   // Check for equality
119   tiledb::Config config1;
120   config1["foo"] = "bar";
121   tiledb::Config config2;
122   config2["foo"] = "bar";
123   bool config_equal = config1 == config2;
124   CHECK(config_equal);
125 
126   // Check for inequality
127   config2["foo"] = "bar2";
128   bool config_not_equal = config1 != config2;
129   CHECK(config_not_equal);
130 }
131 
132 #ifdef TILEDB_SERIALIZATION
133 TEST_CASE(
134     "C++ API: Config Serialization", "[cppapi][cppapi-config][serialization]") {
135   // this variable is parameterized below, but we initialize
136   // here to avoid warning/error on MSVC
137   //   C4701: potentially uninitialized local variable 'format'
138   tiledb_serialization_type_t format = tiledb_serialization_type_t::TILEDB_JSON;
139   SECTION("- json") {
140     format = tiledb_serialization_type_t::TILEDB_JSON;
141   }
142 
143   SECTION("- capnp") {
144     format = tiledb_serialization_type_t::TILEDB_CAPNP;
145   }
146   // Check for equality
147   tiledb::Config config1;
148   config1["foo"] = "bar";
149 
150   tiledb::Context ctx;
151 
152   // Serialize the query (client-side).
153   tiledb_buffer_t* buff1;
154   int32_t rc = tiledb_serialize_config(
155       ctx.ptr().get(), config1.ptr().get(), format, 1, &buff1);
156   CHECK(rc == TILEDB_OK);
157 
158   tiledb_config_t* config2_ptr;
159   rc = tiledb_deserialize_config(
160       ctx.ptr().get(), buff1, format, 0, &config2_ptr);
161   CHECK(rc == TILEDB_OK);
162   tiledb::Config config2(&config2_ptr);
163 
164   bool config_equal = config1 == config2;
165   CHECK(config_equal);
166 
167   // Check for inequality
168   CHECK(config2.get("foo") == std::string("bar"));
169 
170   tiledb_buffer_free(&buff1);
171 }
172 #endif  // TILEDB_SERIALIZATION
173