11 #include <catch2/catch_test_macros.hpp>
12 #include <catch2/matchers/catch_matchers_string.hpp>
36 SCENARIO(
"NMODL can accept CR as return char for one line comment",
"[parser]") {
37 GIVEN(
"A comment defined with CR as return char") {
48 SCENARIO("NMODL can define macros using DEFINE keyword",
"[parser]") {
49 GIVEN(
"A valid macro definition") {
50 WHEN(
"DEFINE NSTEP 6") {
51 THEN(
"parser accepts without an error") {
55 WHEN(
"DEFINE NSTEP 6") {
56 THEN(
"parser accepts without an error") {
62 GIVEN(
"A macro with nested definition is not supported") {
63 WHEN(
"DEFINE SIX 6 DEFINE NSTEP SIX") {
64 THEN(
"parser throws an error") {
66 Catch::Matchers::ContainsSubstring(
"unexpected INVALID_TOKEN"));
71 GIVEN(
"A invalid macro definition with float value") {
72 WHEN(
"DEFINE NSTEP 6.0") {
73 THEN(
"parser throws an exception") {
75 Catch::Matchers::ContainsSubstring(
"unexpected REAL"));
80 GIVEN(
"A invalid macro definition with name and without value") {
81 WHEN(
"DEFINE NSTEP") {
82 THEN(
"parser throws an exception") {
84 Catch::Matchers::ContainsSubstring(
"expecting INTEGER"));
89 GIVEN(
"A invalid macro definition with name and value as a name") {
90 WHEN(
"DEFINE NSTEP SIX") {
91 THEN(
"parser throws an exception") {
93 Catch::Matchers::ContainsSubstring(
"expecting INTEGER"));
98 GIVEN(
"A invalid macro definition without name but with value") {
100 THEN(
"parser throws an exception") {
102 Catch::Matchers::ContainsSubstring(
"expecting NAME"));
108 SCENARIO(
"Macros can be used anywhere in the mod file") {
115 WHEN("macro is used in parameter definition") {
116 THEN(
"parser accepts without an error") {
122 SCENARIO(
"NMODL parser accepts empty unit specification") {
124 FUNCTION ssCB(kdf(), kds()) (mM) {
128 WHEN("FUNCTION is defined with empty unit") {
129 THEN(
"parser accepts without an error") {
135 SCENARIO(
"NMODL parser running number of valid NMODL constructs") {
137 auto test_case = construct.second;
138 GIVEN(test_case.name) {
139 THEN(
"Parser successfully parses : " + test_case.input) {
146 SCENARIO(
"NMODL parser running number of invalid NMODL constructs") {
148 auto test_case = construct.second;
149 GIVEN(test_case.name) {
150 THEN(
"Parser throws an exception while parsing : " + test_case.input) {
161 SCENARIO(
"Check that the parser doesn't crash when passing invalid INCLUDE constructs") {
162 GIVEN(
"An empty filename") {
164 Catch::Matchers::ContainsSubstring(
"empty filename"));
167 GIVEN(
"An missing included file") {
169 Catch::Matchers::ContainsSubstring(
170 "can not open file : \"unknown.file\""));
173 GIVEN(
"An invalid included file") {
175 Catch::Matchers::ContainsSubstring(
"unexpected End of file"));
179 SCENARIO(
"NEURON block can add CURIE information",
"[parser][represents]") {
180 GIVEN(
"A valid CURIE information statement") {
181 THEN(
"parser accepts without an error") {
187 GIVEN(
"Incomplete CURIE information statement") {
188 THEN(
"parser throws an error") {
190 Catch::Matchers::ContainsSubstring(
"Lexer Error"));
192 Catch::Matchers::ContainsSubstring(
"Lexer Error"));
198 SCENARIO(
"Check parents in valid NMODL constructs") {
203 GIVEN(construct.second.name) {
204 THEN(
"Check the parents in : " + construct.second.input) {
222 GIVEN(
"A differential equation") {
226 WHEN(
prefix +
" EQUATION = " + test_case.equation +
" METHOD = " + test_case.method) {
227 THEN(
prefix +
" SOLUTION = " + test_case.solution) {
228 auto expected_result = test_case.solution;
230 REQUIRE(
result == expected_result);
247 const auto& ast_program =
driver.get_ast();
249 {nmodl::ast::AstNodeType::NEURON_BLOCK});
250 value = *(neuron_blocks.front()->get_token());
253 SCENARIO(
"Check if a NEURON block is parsed with correct location info in its token") {
254 GIVEN(
"A single NEURON block") {
257 std::stringstream ss;
258 std::string neuron_block = R
"(
261 USEION ca READ cai,cao WRITE ica
262 RANGE gcabar, m_inf, tau_m, alph1, alph2, KK, shift
267 REQUIRE(ss.str() == " NEURON at [1.1-5.1] type 296");
Visitor for checking parents of ast nodes
Represent token returned by scanner.
static std::string solve(const std::string &equation, std::string method, bool debug=false)
solve equation using provided method
Class that binds all pieces together for parsing nmodl file.
Visitor for checking parents of ast nodes
Common utility functions for file/dir manipulation.
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
void move(Item *q1, Item *q2, Item *q3)
std::string to_string(const T &obj)
custom type to represent nmodl construct for testing
std::map< std::string, NmodlTestCase > const nmodl_valid_constructs
std::map< std::string, NmodlTestCase > const nmodl_invalid_constructs
Guidelines for adding nmodl text constructs.
std::string reindent_text(const std::string &text, int indent_level)
Reindent nmodl text for text-to-text comparison.
std::vector< DiffEqTestCase > const diff_eq_constructs
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
void parse_neuron_block_string(const std::string &name, nmodl::ModToken &value)
std::string solve_construct(const std::string &equation, std::string method)
bool is_valid_construct(const std::string &construct)
SCENARIO("NMODL can accept CR as return char for one line comment", "[parser]")
Auto generated AST classes declaration.
nmodl::parser::UnitDriver driver
Utility functions for visitors implementation.