9 #include <catch2/catch_test_macros.hpp>
21 using namespace nmodl;
22 using namespace visitor;
24 using namespace test_utils;
32 std::tuple<std::shared_ptr<ast::Program>, std::shared_ptr<units::UnitTable>>
run_units_visitor(
33 const std::string& text) {
36 const auto& ast =
driver.get_ast();
40 UnitsVisitor units_visitor = UnitsVisitor(units_lib_path);
42 units_visitor.visit_program(*ast);
47 std::shared_ptr<units::UnitTable> unit_table = units_driver.
table;
50 CheckParentVisitor().check_ast(*ast);
52 return {ast, unit_table};
78 for (
const auto& unit_def: unit_defs) {
79 auto unit_name = unit_def->get_node_name();
80 unit_name.erase(remove_if(unit_name.begin(), unit_name.end(), isspace), unit_name.end());
81 auto unit = unit_table.
get_unit(unit_name);
82 ss << fmt::format(
"{} {:g}:", unit_name, unit->get_factor());
87 for (
const auto& dimension: unit->get_dimensions()) {
118 std::stringstream ss;
120 for (
const auto& factor_def: factor_defs) {
121 const auto& factor_def_cast = std::dynamic_pointer_cast<const ast::FactorDef>(factor_def);
122 ss << fmt::format(
"{} {}\n",
123 factor_def_cast->get_node_name(),
124 factor_def_cast->get_value()->get_value());
129 SCENARIO(
"Parse UNITS block of mod files using Units Visitor",
"[visitor][units]") {
130 GIVEN(
"UNITS block with different cases of UNITS definitions") {
131 static const std::string nmodl_text = R
"(
136 (uS) = (microsiemens)
144 (fAm) = (femto amp meter)
148 (mA/cm2) = (nanoamp/cm2)
149 (molar) = (1 / liter)
151 (mse-1) = (1/millisec)
155 FARADAY1 = (faraday) (coulomb)
156 FARADAY2 = (faraday) (kilocoulombs)
157 FARADAY3 = (faraday) (10000 coulomb)
159 R1 = (k-mole) (joule/degC)
160 R2 = 8.314 (volt-coul/degC)
161 R3 = (mole k) (mV-coulomb/degC)
162 R4 = 8.314 (volt-coul/degK)
163 R5 = 8.314500000000001 (volt coul/kelvin)
164 dummy1 = 123.45 (m 1/sec2)
165 dummy2 = 123.45e3 (millimeters/sec2)
166 dummy3 = 12345e-2 (m/sec2)
167 KTOMV = 0.0853 (mV/degC)
168 B = 0.26 (mM-cm2/mA-ms)
172 oldJ = (R-mole) (1) : compute oldJ based on the value of R which is registered in the UnitTable
173 R = 8 (joule/degC) : define a new value for R that should be visible only in the mod file
174 J = (R-mole) (1) : recalculate J. It's value should be the same as oldJ because R shouldn't change in the UnitTable
175 (myR) = (8 joule/degC) : Define my own R and mole and compute myRnew and myJ based on them
178 myJ = (myR-mymole) (1)
182 static const std::string unit_definitions = R
"(
183 nA 1e-09: sec-1 coul1
184 mA 0.001: sec-1 coul1
185 mV 0.001: m2 kg1 sec-2 coul-1
186 uS 1e-06: m-2 kg-1 sec1 coul2
187 nS 1e-09: m-2 kg-1 sec1 coul2
188 pS 1e-12: m-2 kg-1 sec1 coul2
189 umho 1e-06: m-2 kg-1 sec1 coul2
194 fAm 1e-15: m1 sec-1 coul1
198 mA/cm2 1e-05: m-2 sec-1 coul1
200 S 1: m-2 kg-1 sec1 coul2
205 myR 8: m2 kg1 sec-2 K-1
206 mymole 6e+23: constant
209 static const std::string factor_definitions = R
"(
210 FARADAY1 0x1.78e555060882cp+16
211 FARADAY2 0x1.81f0fae775425p+6
212 FARADAY3 0x1.34c0c8b92a9b7p+3
213 pi 0x1.921fb54442d18p+1
214 R1 0x1.0a1013e8990bep+3
216 R3 0x1.03d3b37125759p+13
227 oldJ 0x1.0912acba81b67p+82
229 J 0x1.0912acba81b67p+82
231 myJ 0x1.fc3842bd1f072p+81
234 THEN("Print the units that were added") {
236 auto expected_result_unit_definitions =
reindent_text(unit_definitions);
237 auto expected_result_factor_definitions =
reindent_text(factor_definitions);
241 auto reindented_result_unit_definitions =
reindent_text(generated_unit_definitions);
242 auto reindented_result_factor_definitions =
reindent_text(generated_factor_definitions);
243 REQUIRE(reindented_result_unit_definitions == expected_result_unit_definitions);
244 REQUIRE(reindented_result_factor_definitions == expected_result_factor_definitions);
247 GIVEN(
"UNITS block with Unit definition which is already defined") {
248 static const std::string nmodl_text = R
"(
253 THEN("Throw redefinition exception") {