1 /*
2 * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4 * For use in publications, see ACKNOWLEDGE.TXT
5 */
6
7 #include <vector>
8 #include "alps/params.hpp"
9 #include "gtest/gtest.h"
10
11 #include "param_generators.hpp"
12
13 #define ALPS_ASSIGN_PARAM(a_type) parms[ #a_type ] = static_cast<a_type>(0x41)
14
15 #define ALPS_TEST_PARAM(a_type) do { a_type x=parms[ #a_type ]; EXPECT_EQ(x,0x41); } while(0)
16
17 // Used to suppress "unused variable" warning.
dummy_use(const void *)18 static inline void dummy_use(const void*) {};
19
TEST(param,assignments)20 TEST(param,assignments)
21 {
22 alps::params parms;
23
24 // ALPS_ASSIGN_PARAM(char);
25 // ALPS_ASSIGN_PARAM(signed char);
26 // ALPS_ASSIGN_PARAM(unsigned char);
27 // ALPS_ASSIGN_PARAM(short);
28 // ALPS_ASSIGN_PARAM(unsigned short);
29 ALPS_ASSIGN_PARAM(int);
30 ALPS_ASSIGN_PARAM(unsigned);
31 ALPS_ASSIGN_PARAM(long);
32 ALPS_ASSIGN_PARAM(unsigned long);
33 // ALPS_ASSIGN_PARAM(long long);
34 // ALPS_ASSIGN_PARAM(unsigned long long);
35 // ALPS_ASSIGN_PARAM(float);
36 ALPS_ASSIGN_PARAM(double);
37 // ALPS_ASSIGN_PARAM(long double);
38
39 parms["bool"] = true;
40 parms["cstring"] = "asdf";
41 parms["std::string"] = std::string("asdf");
42
43 std::vector<double> vd(3);
44 vd[0]=1.; vd[1]=2.; vd[2]=4.;
45 parms["dblvec"] = vd;
46
47 // ALPS_TEST_PARAM(char);
48 // ALPS_TEST_PARAM(signed char);
49 // ALPS_TEST_PARAM(unsigned char);
50 // ALPS_TEST_PARAM(short);
51 // ALPS_TEST_PARAM(unsigned short);
52 ALPS_TEST_PARAM(int);
53 // ALPS_TEST_PARAM(unsigned);
54 ALPS_TEST_PARAM(long);
55 // ALPS_TEST_PARAM(unsigned long);
56 // ALPS_TEST_PARAM(long long);
57 // ALPS_TEST_PARAM(unsigned long long);
58 // ALPS_TEST_PARAM(float);
59 ALPS_TEST_PARAM(double);
60 // ALPS_TEST_PARAM(long double);
61
62 EXPECT_TRUE(bool(parms["bool"]));
63
64 EXPECT_EQ(parms["cstring"],std::string("asdf"));
65 EXPECT_EQ(parms["std::string"],std::string("asdf"));
66
67 EXPECT_EQ(parms["dblvec"],vd);
68 }
69
TEST(param,StringAssignments)70 TEST(param, StringAssignments)
71 {
72 alps::params p;
73 p["std::string"]=std::string("a string");
74 p["cstring"]="C-string";
75
76 {
77 EXPECT_THROW({char* s=p["cstring"]; dummy_use(&s);}, alps::params::type_mismatch);
78 EXPECT_THROW({const char* cs=p["cstring"]; dummy_use(&cs);}, alps::params::type_mismatch);
79 EXPECT_THROW({const char* cs=p["std::string"]; dummy_use(&cs);}, alps::params::type_mismatch);
80 }
81
82 {
83 const char* s1=p["cstring"].as<std::string>().c_str();
84 EXPECT_TRUE(strcmp("C-string",s1)==0);
85
86 const char* s2=p["std::string"].as<std::string>().c_str();
87 EXPECT_TRUE(strcmp("a string",s2)==0);
88 }
89
90 {
91 std::string s1=p["cstring"];
92 EXPECT_EQ(s1,"C-string");
93
94 std::string s2=p["std::string"];
95 EXPECT_EQ(s2,"a string");
96 }
97
98 // This will not compile:
99 /*
100 {
101 std::string s1; s1=p["cstring"];
102 EXPECT_EQ(s1,"C-string");
103
104 std::string s2; s2=p["std::string"];
105 EXPECT_EQ(s2,"a string");
106 }
107 */
108
109 {
110 std::string s1; s1=p["cstring"].as<std::string>();
111 EXPECT_EQ(s1,"C-string");
112
113 std::string s2; s2=p["std::string"].as<std::string>();
114 EXPECT_EQ(s2,"a string");
115 }
116 }
117
118
119
120
121 // Testing explicitly assigned/implicitly defined parameters and implicit type conversion
TEST(param,ImplicitDefine)122 TEST(param,ImplicitDefine)
123 {
124 const char* argv[]={"THIS PROGRAM", "--param1=abc", "--param2=4.25"};
125 const int argc=sizeof(argv)/sizeof(*argv);
126
127 alps::params p(argc,argv);
128
129 // Explicitly assigning a parameter
130 p["param1"]=3.125;
131 EXPECT_EQ(p["param1"],3.125);
132
133 {
134 // It is not a string, whatever command line is
135 EXPECT_THROW({const std::string& s=p["param1"]; dummy_use(&s);}, alps::params::type_mismatch);
136
137 // It is not an int either
138 EXPECT_THROW({int n=p["param1"]; dummy_use(&n);}, alps::params::type_mismatch);
139 }
140
141 // String cannot be assigned to it
142 EXPECT_THROW(p["param1"]="abc", alps::params::type_mismatch);
143
144 // Integer can be assigned to it...
145 p["param1"]=3;
146 // ...but it is still not an integer:
147 {
148 EXPECT_THROW({int n=p["param1"]; dummy_use(&n);}, alps::params::type_mismatch);
149 }
150
151 // It cannot be defined now, once it was assigned
152 EXPECT_THROW((p.define<double>("param1", "Double parameter")), alps::params::extra_definition);
153
154 // Defining another parameter
155 p.define<double>("param2", "Another double parameter");
156
157 // Redefinition of the same parameter
158 EXPECT_THROW((p.define<double>("param2", "Double parameter again")), alps::params::double_definition);
159 EXPECT_THROW((p.define<int>("param2", "Int parameter now")), alps::params::double_definition);
160
161 // Reading the parameter
162 EXPECT_EQ(4.25, p["param2"]);
163
164 // Assigning to and from the parameter
165
166 // Assign double --- should work
167 p["param2"]=5.0;
168 EXPECT_EQ(5.0, p["param2"]);
169
170 // Assign int --- should work, but remain double
171 p["param2"]=5;
172 {
173 EXPECT_THROW({int n=p["param2"]; dummy_use(&n);}, alps::params::type_mismatch);
174 }
175
176 EXPECT_THROW(p["param2"]="abc", alps::params::type_mismatch);
177 }
178
179 // Test object invariants: defining a parameter or parsing a file should not affect the visible state
TEST(param,Invariance)180 TEST(param,Invariance)
181 {
182 const char* argv[]={"THIS PROGRAM", "--str=abc", "--int1=111", "--int2=222" };
183 const int argc=sizeof(argv)/sizeof(*argv);
184
185 alps::params p(argc,argv);
186
187 p["int3"]=333;
188
189 // Define the string parameter
190 p.define<std::string>("str","String parameter");
191 // Check the state (triggers parsing!)
192 EXPECT_EQ(333, p["int3"]);
193 EXPECT_EQ(std::string("abc"), p["str"]);
194
195 // Define the int1 parameter
196 p.define<int>("int1","Int parameter1");
197 // Check the state (triggers parsing!)
198 EXPECT_EQ(std::string("abc"), p["str"]);
199 EXPECT_EQ(111, p["int1"]);
200 EXPECT_EQ(333, p["int3"]);
201
202 // Change the state
203 p["int3"]=-3333;
204 p["int1"]=-1111;
205
206 // Define the int2 parameter
207 p.define<int>("int2","Int parameter2");
208 // Check the state (triggers parsing!)
209 EXPECT_EQ(222, p["int2"]);
210 EXPECT_EQ(std::string("abc"), p["str"]);
211 EXPECT_EQ(-1111, p["int1"]);
212 EXPECT_EQ(-3333, p["int3"]);
213
214 // Define a non-exisiting parameter
215 p.define<int>("int4","Int parameter4 (not provided)");
216 // Check the state (triggers parsing!)
217 EXPECT_EQ(222, p["int2"]);
218 EXPECT_EQ(std::string("abc"), p["str"]);
219 EXPECT_EQ(-1111, p["int1"]);
220 EXPECT_EQ(-3333, p["int3"]);
221 }
222
223
224 // FIXME: test type mismatch (on get and on set) systematically for all scalar and vector types
225
226
227 // Testing type mismatch exception and message
TEST(param,SetTypeMismatchMessage)228 TEST(param,SetTypeMismatchMessage)
229 {
230 alps::params_ns::testing::CmdlineParameter<int> gen_int("myparam");
231 alps::params p=gen_int.params();
232
233 // FIXME: probably deserve a separate test
234 EXPECT_TRUE( p.exists<int>("myparam") );
235 EXPECT_FALSE( p.exists<std::string>("myparam") );
236
237 bool thrown=false;
238 try {
239 p["myparam"]=1L; // attempt to assing long to an integer parameter
240 } catch (alps::params::type_mismatch& exc) {
241 thrown=true;
242 std::string msg=exc.what();
243 // std::cerr << "DEBUG: msg='" << msg << "'\n";
244 EXPECT_TRUE(msg.find("myparam")!=std::string::npos) << "Option name is not mentioned in exception message: "+msg;
245 EXPECT_TRUE(msg.find("int")!=std::string::npos) << "Option type is not mentioned in exception message: "+msg;
246 EXPECT_TRUE(msg.find("long")!=std::string::npos) << "RHS type is not mentioned in exception message: "+msg;
247 }
248 EXPECT_TRUE(thrown) << "Exception was not thrown!";
249 }
250
251 // Testing type mismatch exception and message
TEST(param,GetTypeMismatchMessage)252 TEST(param,GetTypeMismatchMessage)
253 {
254 alps::params_ns::testing::CmdlineParameter<long> gen_long("myparam");
255 alps::params p=gen_long.params();
256
257 bool thrown=false;
258 try {
259 std::string s=p["myparam"]; // attempt to assing integer parameter to a string
260 } catch (alps::params::type_mismatch& exc) {
261 thrown=true;
262 std::string msg=exc.what();
263 // std::cerr << "DEBUG: msg='" << msg << "'\n";
264 EXPECT_TRUE(msg.find("myparam")!=std::string::npos) << "Option name is not mentioned in exception message: "+msg;
265 EXPECT_TRUE(msg.find("long")!=std::string::npos) << "Option type is not mentioned in exception message: "+msg;
266 EXPECT_TRUE(msg.find("std::string")!=std::string::npos) << "LHS type is not mentioned in exception message: "+msg;
267 }
268 EXPECT_TRUE(thrown) << "Exception was not thrown!";
269 }
270