1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2016 Couchbase, Inc
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include "configuration.h"
20 #include "configuration_impl.h"
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
25 /* Like EXPECT_THROW except you can check the exception's `what()` */
26 # define CB_EXPECT_THROW_MSG(EXPR, ETYPE, MSG) \
27 EXPECT_THROW(EXPR, ETYPE); \
30 ADD_FAILURE() << "Expected: " #EXPR " throws an exception of type " \
31 #ETYPE ".\n Actual: it throws nothing."; \
32 } catch (const ETYPE& EXCEPTION) { \
33 EXPECT_STREQ(MSG, EXCEPTION.what()) << "Wrong exception message!" ; \
35 ADD_FAILURE() << "Expected: " #EXPR " throws an exception of type " \
36 #ETYPE ".\n Actual: it throws different type."; \
39 TEST(ValueChangedValidatorTest, AllMethodsThrow) {
40 ValueChangedValidator validator;
41 std::string key{"test_key"};
43 EXPECT_THROW(validator.validateBool(key, false), std::runtime_error);
44 EXPECT_THROW(validator.validateSize(key, 0), std::runtime_error);
45 EXPECT_THROW(validator.validateSSize(key, 0), std::runtime_error);
46 EXPECT_THROW(validator.validateFloat(key, 0.0), std::runtime_error);
47 EXPECT_THROW(validator.validateString(key, ""), std::runtime_error);
50 TEST(SizeRangeValidatorTest, UninitialisedIsOnlyZero) {
51 SizeRangeValidator validator;
52 std::string key{"test_key"};
54 EXPECT_NO_THROW(validator.validateSize(key, 0));
55 EXPECT_NO_THROW(validator.validateSSize(key, 0));
58 validator.validateSize(key, 1),
60 "Validation Error, test_key takes values between 0 and 0 (Got: 1)"
63 validator.validateSSize(key, 1),
65 "Validation Error, test_key takes values between 0 and 0 (Got: 1)"
68 validator.validateSSize(key, -1),
70 "Validation Error, test_key takes values between 0 and 0 (Got: -1)"
74 TEST(SizeRangeValidatorTest, UnsignedBoundsWorks) {
75 SizeRangeValidator validator;
76 std::string key{"test_key"};
78 (&validator)->min(100)->max(1000);
80 EXPECT_NO_THROW(validator.validateSize(key, 100));
81 EXPECT_NO_THROW(validator.validateSize(key, 1000));
82 EXPECT_NO_THROW(validator.validateSize(key, 101));
83 EXPECT_NO_THROW(validator.validateSize(key, 999));
86 validator.validateSize(key, 99),
88 "Validation Error, test_key takes values between 100 and 1000 (Got: 99)"
91 validator.validateSize(key, 1001),
93 "Validation Error, test_key takes values between 100 and 1000 (Got: 1001)"
97 TEST(SizeRangeValidatorTest, SignedBoundsWorks) {
98 SizeRangeValidator validator;
99 std::string key{"test_key"};
101 (&validator)->min(-100)->max(1000);
103 EXPECT_NO_THROW(validator.validateSSize(key, -100));
104 EXPECT_NO_THROW(validator.validateSSize(key, 1000));
105 EXPECT_NO_THROW(validator.validateSSize(key, -99));
106 EXPECT_NO_THROW(validator.validateSSize(key, 999));
109 validator.validateSSize(key, -101),
111 "Validation Error, test_key takes values between -100 and 1000 (Got: -101)"
114 validator.validateSSize(key, 1001),
116 "Validation Error, test_key takes values between -100 and 1000 (Got: 1001)"
120 TEST(SSizeRangeValidatorTest, UninitialisedIsOnlyZero) {
121 SizeRangeValidator validator;
122 std::string key{"test_key"};
124 EXPECT_NO_THROW(validator.validateSSize(key, 0));
127 validator.validateSSize(key, 1),
129 "Validation Error, test_key takes values between 0 and 0 (Got: 1)"
132 validator.validateSSize(key, -1),
134 "Validation Error, test_key takes values between 0 and 0 (Got: -1)"
138 TEST(SSizeRangeValidatorTest, SignedBoundsWork) {
139 SSizeRangeValidator validator;
140 std::string key{"test_key"};
142 (&validator)->min(-100)->max(1000);
144 EXPECT_NO_THROW(validator.validateSSize(key, -100));
145 EXPECT_NO_THROW(validator.validateSSize(key, 1000));
146 EXPECT_NO_THROW(validator.validateSSize(key, -99));
147 EXPECT_NO_THROW(validator.validateSSize(key, 999));
150 validator.validateSSize(key, -101),
152 "Validation Error, test_key takes values between -100 and 1000 (Got: -101)"
155 validator.validateSSize(key, 1001),
157 "Validation Error, test_key takes values between -100 and 1000 (Got: 1001)"
161 TEST(FloatRangeValidatorTest, UninitialisedIsZero) {
162 FloatRangeValidator validator;
163 std::string key{"test_key"};
165 validator.validateFloat(key, 0.0);
167 validator.validateFloat(key, 1.0),
169 "Validation Error, test_key takes values between 0.000000 and 0.000000 (Got: 1.000000)"
174 TEST(FloatRangeValidatorTest, FloatBoundsWork) {
175 FloatRangeValidator validator;
176 std::string key{"test_key"};
178 (&validator)->min(-100.1)->max(1000.1);
181 EXPECT_NO_THROW(validator.validateFloat(key, -100.1));
182 EXPECT_NO_THROW(validator.validateFloat(key, 100.00));
183 EXPECT_NO_THROW(validator.validateFloat(key, 101.0));
184 EXPECT_NO_THROW(validator.validateFloat(key, 999.0));
188 validator.validateFloat(key, -100.2),
190 ("Validation Error, test_key takes values between "
191 + std::to_string(-100.1f)
192 + " and " + std::to_string(1000.1f)
193 + " (Got: " + std::to_string(-100.2f) + ")").c_str()
196 validator.validateFloat(key, 1000.2),
198 ("Validation Error, test_key takes values between "
199 + std::to_string(-100.1f)
200 + " and " + std::to_string(1000.1f)
201 + " (Got: " + std::to_string(1000.2f) + ")").c_str()
205 TEST(EnumValidatorTest, EmptyWorks) {
206 EnumValidator validator;
207 std::string key{"test_key"};
211 validator.validateString(key, "my_enum"),
213 "Validation Error, test_key takes one of [] (Got: my_enum)"
217 TEST(EnumValidatorTest, AddOneWorks) {
218 EnumValidator validator;
219 std::string key{"test_key"};
221 /* Single test, in-bounds */
222 validator.add("enum_one");
223 EXPECT_NO_THROW(validator.validateString(key, "enum_one"));
225 /* Single test, out of bounds */
227 validator.validateString(key, "my_enum"),
229 "Validation Error, test_key takes one of [enum_one] (Got: my_enum)"
233 TEST(EnumValidatorTest, OverwriteWorks) {
234 EnumValidator validator;
235 std::string key{"test_key"};
237 validator.add("enum_one");
238 validator.add("enum_one");
239 EXPECT_NO_THROW(validator.validateString(key, "enum_one"));
242 TEST(EnumValidatorTest, MultipleWorks) {
243 EnumValidator validator;
244 std::string key{"test_key"};
246 validator.add("enum_1");
247 validator.add("enum_2");
248 validator.add("enum_3");
249 EXPECT_NO_THROW(validator.validateString(key, "enum_1"));
250 EXPECT_NO_THROW(validator.validateString(key, "enum_2"));
251 EXPECT_NO_THROW(validator.validateString(key, "enum_3"));
253 /* Multi, out of bounds */
255 validator.validateString(key, "my_enum"),
257 "Validation Error, test_key takes one of [enum_1, enum_2, enum_3] (Got: my_enum)"
261 TEST(EnumValidatorTest, EnMassWorks) {
262 EnumValidator validator;
263 std::string key{"test_key"};
266 std::vector<std::string> mass;
267 for(auto i = 0; i < 100000; i++) {
268 mass.push_back(std::to_string(i));
272 validator.add(i.c_str());
275 EXPECT_NO_THROW(validator.validateString(key, i.c_str()));
280 class ConfigurationShim : public Configuration {
282 * Shim class to allow testing the protected methods which are usually
283 * exposed through the generated configuration.
287 using Configuration::setParameter;
288 using Configuration::getParameter;
291 TEST(ConfigurationTest, SetGetWorks) {
292 ConfigurationShim configuration;
294 configuration.setParameter("bool", false);
295 EXPECT_EQ(configuration.getParameter<bool>("bool"), false);
297 configuration.setParameter("size", (size_t)100);
298 EXPECT_EQ(configuration.getParameter<size_t>("size"), 100);
300 configuration.setParameter("ssize", (ssize_t)-100);
301 EXPECT_EQ(configuration.getParameter<ssize_t>("ssize"), -100);
303 configuration.setParameter("float", (float)123.5);
304 EXPECT_EQ(configuration.getParameter<float>("float"), 123.5);
306 configuration.setParameter("char*", "hello");
307 EXPECT_EQ(configuration.getParameter<std::string>("char*"), "hello");
309 configuration.setParameter("string", std::string("hello"));
310 EXPECT_EQ(configuration.getParameter<std::string>("string"), "hello");
313 TEST(ConfigurationTest, ValidatorWorks) {
314 ConfigurationShim configuration;
315 std::string key{"test_key"};
317 configuration.setParameter(key, (size_t)110);
318 EXPECT_NO_THROW(configuration.setValueValidator(key, (new SizeRangeValidator())->min(10)->max(100)));
319 EXPECT_NO_THROW(configuration.setParameter(key, (size_t)10));
320 EXPECT_NO_THROW(configuration.setParameter(key, (size_t)100));
321 EXPECT_THROW(configuration.setParameter(key, (size_t)9), std::range_error);
323 CB_EXPECT_THROW_MSG(configuration.setParameter(key, (size_t)9),
325 "Validation Error, test_key takes values between 10 "
329 class MockValueChangedListener : public ValueChangedListener {
331 MOCK_METHOD2(booleanValueChanged, void(const std::string&, bool));
332 MOCK_METHOD2(sizeValueChanged, void(const std::string&, size_t));
333 MOCK_METHOD2(ssizeValueChanged, void(const std::string&, ssize_t));
334 MOCK_METHOD2(floatValueChanged, void(const std::string&, float));
335 MOCK_METHOD2(stringValueChanged, void(const std::string&, const char*));
340 TEST(ChangeListenerTest, ChangeListenerSSizeRegression) {
342 * Confirming that setting a config parameter of type ssize_t
343 * correctly calls ssizeValueChanged on Changelisteners. Previously, it
344 * instead called sizeValueChanged - and some code had become dependent on
347 ConfigurationShim configuration;
348 std::string key{"test_key"};
351 auto mvcl = new MockValueChangedListener;
352 // set parameter once so entry in attributes is present to add a listener
353 configuration.setParameter(key, (ssize_t)1);
355 EXPECT_CALL(*mvcl, ssizeValueChanged("test_key", 2)).Times(1);
356 EXPECT_CALL(*mvcl, sizeValueChanged(_, _)).Times(0);
359 configuration.addValueChangedListener(key, mvcl);
362 configuration.setParameter(key, (ssize_t)2);