11 #include <catch2/catch_test_macros.hpp>
12 #include <catch2/matchers/catch_matchers_string.hpp>
20 using namespace nmodl;
21 using namespace symtab;
22 using namespace syminfo;
28 SCENARIO(
"Symbol properties can be added and converted to string") {
33 GIVEN(
"A empty property") {
34 WHEN(
"converted to string") {
35 THEN(
"returns empty string") {
39 WHEN(
"checked for property") {
40 THEN(
"doesn't have any property") {
44 WHEN(
"adding another empty property") {
46 THEN(
"to_string still returns empty string") {
50 WHEN(
"added some other property") {
52 THEN(
"to_string returns added property") {
55 WHEN(
"checked for property") {
56 THEN(
"has required property") {
61 WHEN(
"added multiple properties") {
64 THEN(
"to_string returns all added properties") {
65 REQUIRE_THAT(
to_string(result), Catch::Matchers::ContainsSubstring(
"local"));
66 REQUIRE_THAT(
to_string(result), Catch::Matchers::ContainsSubstring(
"global"));
67 REQUIRE_THAT(
to_string(result), Catch::Matchers::ContainsSubstring(
"write_ion"));
69 WHEN(
"checked for property") {
70 THEN(
"has all added properties") {
78 WHEN(
"properties manipulated with bitwise operators") {
79 THEN(
"& applied correctly") {
82 NmodlType result3 = prop1 & prop2 & prop3;
96 SCENARIO(
"Multiple properties can be added to Symbol") {
102 Symbol symbol(
"alpha", token);
103 WHEN(
"added external property") {
105 THEN(
"symbol becomes external") {
109 WHEN(
"added multiple properties to symbol") {
112 THEN(
"symbol has multiple properties") {
120 auto property = property1 | property2;
123 property |= property3;
126 property = property2 | property3;
133 WHEN(
"remove properties from symbol") {
136 THEN(
"remove property that exists") {
141 THEN(
"remove property that doesn't exist") {
145 auto properties = property1 | property2;
149 WHEN(
"combined properties") {
151 THEN(
"symbol has union of all properties") {
166 SCENARIO(
"Symbol table allows operations like insert, lookup") {
167 GIVEN(
"A global SymbolTable") {
168 auto program = std::make_shared<ast::Program>();
169 auto table = std::make_shared<SymbolTable>(
"Na", program.get(),
true);
170 auto symbol = std::make_shared<Symbol>(
"alpha");
172 WHEN(
"checked methods and member variables") {
173 THEN(
"all members are initialized") {
174 REQUIRE(table->under_global_scope());
175 REQUIRE_THAT(table->name(), Catch::Matchers::ContainsSubstring(
"Na"));
176 REQUIRE_THAT(table->get_parent_table_name(),
177 Catch::Matchers::ContainsSubstring(
"None"));
178 REQUIRE_THAT(table->position(), Catch::Matchers::ContainsSubstring(
"UNKNOWN"));
181 WHEN(
"insert symbol") {
182 table->insert(symbol);
183 THEN(
"table size increases") {
184 REQUIRE(table->symbol_count() == 1);
186 THEN(
"lookup returns an inserted symbol") {
187 REQUIRE(table->lookup(
"alpha") !=
nullptr);
188 REQUIRE(table->lookup(
"beta") ==
nullptr);
190 WHEN(
"re-inserting the same symbol") {
191 THEN(
"throws an exception") {
192 REQUIRE_THROWS_WITH(table->insert(symbol),
193 Catch::Matchers::ContainsSubstring(
"re-insert"));
196 WHEN(
"inserting another symbol") {
197 auto next_symbol = std::make_shared<Symbol>(
"beta");
198 table->insert(next_symbol);
199 THEN(
"symbol gets added and table size increases") {
200 REQUIRE(table->symbol_count() == 2);
201 REQUIRE(table->lookup(
"beta") !=
nullptr);
205 WHEN(
"checked for global variables") {
206 table->insert(symbol);
208 THEN(
"table doesn't have any global variables") {
209 REQUIRE(variables.empty());
210 WHEN(
"added global symbol") {
211 auto next_symbol = std::make_shared<Symbol>(
"gamma");
213 table->insert(next_symbol);
214 auto variables = table->get_variables_with_properties(
216 THEN(
"table has global variable") {
217 REQUIRE(variables.size() == 1);
222 WHEN(
"added another symbol table as children") {
223 table->insert(symbol);
224 auto next_program = std::make_shared<ast::Program>();
225 auto next_table = std::make_shared<SymbolTable>(
"Ca", next_program.get(),
true);
226 next_table->set_parent_table(table.get());
227 THEN(
"children symbol table can lookup into parent table scope") {
228 REQUIRE(next_table->lookup(
"alpha") ==
nullptr);
229 REQUIRE(next_table->lookup_in_scope(
"alpha") !=
nullptr);
231 THEN(
"children can figure if it is in global scope or not") {
232 REQUIRE(next_table->global_scope() == table->global_scope());
235 WHEN(
"pretty-printing a symbol table to a stream") {
236 std::ostringstream oss;
237 table->print(oss, 0);
238 auto text = oss.str();
239 THEN(
"nothing is written when the table is empty") {
240 REQUIRE(text.empty());
242 table->insert(symbol);
243 table->print(oss, 0);
245 THEN(
"the symbol present in the table can be found in the written string") {
246 REQUIRE(text.find(symbol->get_name()) != std::string::npos);
249 WHEN(
"creating a clone of symbol table") {
250 const std::unique_ptr<SymbolTable> clone(table->clone());
251 THEN(
"clone has the same name") {
252 REQUIRE(clone->
name() == table->name());
255 WHEN(
"query for symbol with and without properties") {
256 auto symbol1 = std::make_shared<Symbol>(
"alpha");
257 auto symbol2 = std::make_shared<Symbol>(
"beta");
258 auto symbol3 = std::make_shared<Symbol>(
"gamma");
259 auto symbol4 = std::make_shared<Symbol>(
"delta");
268 table->insert(symbol1);
269 table->insert(symbol2);
270 table->insert(symbol3);
271 table->insert(symbol4);
274 REQUIRE(result.size() == 4);
278 REQUIRE(result.size() == 4);
282 result = table->get_variables(with, without);
283 REQUIRE(result.size() == 1);
284 REQUIRE(result[0]->
get_name() ==
"alpha");
289 result = table->get_variables(with, without);
290 REQUIRE(result.size() == 1);
291 REQUIRE(result[0]->
get_name() ==
"delta");
295 result = table->get_variables(with, without);
296 REQUIRE(result.empty());
305 SCENARIO(
"Global symbol table (ModelSymbol) allows scope based operations") {
306 GIVEN(
"A Model symbolTable") {
309 auto program = std::make_shared<ast::Program>();
310 auto symbol1 = std::make_shared<Symbol>(
"alpha");
311 auto symbol2 = std::make_shared<Symbol>(
"alpha");
312 auto symbol3 = std::make_shared<Symbol>(
"alpha");
320 WHEN(
"trying to exit scope without entering") {
321 THEN(
"throws an exception") {
323 Catch::Matchers::ContainsSubstring(
"without entering"));
326 WHEN(
"trying to enter scope without valid node") {
327 THEN(
"throws an exception") {
328 REQUIRE_THROWS_WITH(mod_symtab.
enter_scope(
"scope",
nullptr,
true, old_symtab),
329 Catch::Matchers::ContainsSubstring(
"empty node"));
332 WHEN(
"trying to insert without entering scope") {
333 THEN(
"throws an exception") {
334 auto symbol = std::make_shared<Symbol>(
"alpha");
335 REQUIRE_THROWS_WITH(mod_symtab.
insert(symbol),
336 Catch::Matchers::ContainsSubstring(
"Can not insert"));
339 WHEN(
"enter scope multiple times") {
340 auto program1 = std::make_shared<ast::Program>();
341 auto program2 = std::make_shared<ast::Program>();
342 mod_symtab.
enter_scope(
"scope1", program1.get(),
false, old_symtab);
343 mod_symtab.
enter_scope(
"scope2", program2.get(),
false, old_symtab);
344 THEN(
"can leave scope multiple times") {
349 WHEN(
"added same symbol with different properties in global scope") {
350 mod_symtab.
enter_scope(
"scope", program.get(),
true, old_symtab);
351 mod_symtab.
insert(symbol1);
352 mod_symtab.
insert(symbol2);
353 THEN(
"only one symbol gets added with combined properties") {
354 auto symbol = mod_symtab.
lookup(
"alpha");
356 REQUIRE(symbol->get_properties() == properties);
359 WHEN(
"added same symbol with existing property") {
360 mod_symtab.
enter_scope(
"scope", program.get(),
true, old_symtab);
361 mod_symtab.
insert(symbol1);
362 mod_symtab.
insert(symbol2);
363 THEN(
"throws an exception") {
364 REQUIRE_THROWS_WITH(mod_symtab.
insert(symbol3),
365 Catch::Matchers::ContainsSubstring(
"Re-declaration"));
368 WHEN(
"added same symbol in children scope") {
369 mod_symtab.
enter_scope(
"scope1", program.get(),
true, old_symtab);
370 mod_symtab.
insert(symbol2);
371 THEN(
"it's ok, just get overshadow warning") {
372 mod_symtab.
enter_scope(
"scope2", program.get(),
false, old_symtab);
373 mod_symtab.
insert(symbol3);
385 GIVEN(
"A symbol can have several nodes") {
386 auto st = std::make_shared<ast::String>(
"node1");
387 auto fl = std::make_shared<ast::Float>(
"1.1");
394 WHEN(
"trying to get name") {
396 REQUIRE(symbol1.
get_name() ==
"alpha");
397 REQUIRE(symbol2.
get_name() ==
"beta");
401 WHEN(
"trying to get all nodes") {
403 REQUIRE(symbol1.
get_nodes().size() == 2);
408 WHEN(
"trying to get specific node") {
412 REQUIRE(nodes.size() == 1);
413 REQUIRE(nodes.front()->is_string());
417 WHEN(
"read and write counters works") {
430 WHEN(
"renaming a symbol") {
432 THEN(
"get_name return the new name") {
433 REQUIRE(symbol2.
get_name() ==
"gamma");
437 THEN(
"get_original_name return the new name") {
442 WHEN(
"set as array") {
444 THEN(
"recognized as an array") {