diff --git a/src/engines/bash-engine.cc b/src/engines/bash-engine.cc index 2f76e049..68787930 100644 --- a/src/engines/bash-engine.cc +++ b/src/engines/bash-engine.cc @@ -619,7 +619,7 @@ class BashEngine : public ScriptEngineBase continue; // While, if, switch endings - if (s == "esac" || s == "fi" || s == "do" || s == "done" || s == "else" || s == "then" || s == "}" || s == "{") + if (s == "esac" || s == "fi" || s == "do" || s == "done" || s == "else" || s == "then" || s == "}" || s == "{" || s == ")" || s == "(") continue; // Functions @@ -684,6 +684,10 @@ class BashEngine : public ScriptEngineBase if ((s[0] == '{' || s[0] == '}') && s.size() == 1) continue; + // Empty parentheses + if ((s[0] == '(' || s[0] == ')') && s.size() == 1) + continue; + // While, if, switch endings if (s == "esac" || s == "fi" || s == "do" || s == "done" || s == "else" || s == "then") continue; @@ -756,8 +760,17 @@ class BashEngine : public ScriptEngineBase if (!arithmeticActive && s.find("let ") != 0 && s.find("$((") == std::string::npos && s.find("))") == std::string::npos && heredocStart != std::string::npos) { - // Skip << and remove spaces before and after "EOF" - heredocMarker = trim_string(s.substr(heredocStart + 2, s.size())); + // Skip << + heredocMarker = s.substr(heredocStart + 2, s.size()); + + if (heredocMarker[0] == '-') + { + // '-' marks tab-suppression in heredoc + heredocMarker = heredocMarker.substr(1); + } + + // Remove spaces before and after "EOF" + heredocMarker = trim_string(heredocMarker); // Make sure the heredoc marker is a word for (unsigned int i = 0; i < heredocMarker.size(); i++) @@ -769,12 +782,6 @@ class BashEngine : public ScriptEngineBase } } - if (heredocMarker[0] == '-') - { - // '-' marks tab-suppression in heredoc - heredocMarker = heredocMarker.substr(1); - } - if (heredocMarker.length() > 2 && (heredocMarker[0] == '"' || heredocMarker[0] == '\'') && heredocMarker[0] == heredocMarker[heredocMarker.length() - 1]) { diff --git a/tests/bash/shell-main b/tests/bash/shell-main index 1d5d0b1e..13f20cf2 100755 --- a/tests/bash/shell-main +++ b/tests/bash/shell-main @@ -178,3 +178,25 @@ booknames=`sqlplus -S -R 3 "$LOGON_STR" <<-EOF exit; EOF` echo $booknames + +# Issue 457 + +cat << EOF +foo +bar +EOF + +cat << "EOF" +foo +bar +EOF + +cat <<- EOF +foo +bar +EOF + +cat <<- "EOF" +foo +bar +EOF diff --git a/tests/bash/subshell.sh b/tests/bash/subshell.sh index 05bf1b55..40d815f8 100755 --- a/tests/bash/subshell.sh +++ b/tests/bash/subshell.sh @@ -6,3 +6,11 @@ echo "Inbetween stuff" (echo "Other subshell" echo More stuff in Other subshell ) + +# Issue 457 + +fn4() ( + echo "fn4" +) + +fn4 diff --git a/tests/tools/test_bash.py b/tests/tools/test_bash.py index 6a522ee8..da51465a 100644 --- a/tests/tools/test_bash.py +++ b/tests/tools/test_bash.py @@ -351,7 +351,7 @@ def runTest(self): dom = cobertura.parseFile(self.outbase + "/kcov/subshell.sh/cobertura.xml") self.assertIsNone(cobertura.hitsPerLine(dom, "subshell.sh", 1)) self.assertEqual(2, cobertura.hitsPerLine(dom, "subshell.sh", 4)) - self.assertEqual(0, cobertura.hitsPerLine(dom, "subshell.sh", 8)) + assert cobertura.hitsPerLine(dom, "subshell.sh", 8) is None class bash_handle_all_output(libkcov.TestCase): @@ -512,3 +512,48 @@ def runTest(self): ) self.assertIsNone(cobertura.hitsPerLine(dom, "long-output-without-return.sh", 1)) self.assertEqual(32768, cobertura.hitsPerLine(dom, "long-output-without-return.sh", 4)) + + +# Issue 457 +class bash_heredoc_with_space(libkcov.TestCase): + def runTest(self): + rv, o = self.do( + self.kcov + " " + self.outbase + "/kcov " + self.sources + "/tests/bash/shell-main" + ) + + dom = cobertura.parseFile(self.outbase + "/kcov/shell-main/cobertura.xml") + + assert cobertura.hitsPerLine(dom, "shell-main", 184) == 1 + assert cobertura.hitsPerLine(dom, "shell-main", 185) is None + assert cobertura.hitsPerLine(dom, "shell-main", 186) is None + assert cobertura.hitsPerLine(dom, "shell-main", 187) is None + + assert cobertura.hitsPerLine(dom, "shell-main", 189) == 1 + assert cobertura.hitsPerLine(dom, "shell-main", 190) is None + assert cobertura.hitsPerLine(dom, "shell-main", 191) is None + assert cobertura.hitsPerLine(dom, "shell-main", 192) is None + + assert cobertura.hitsPerLine(dom, "shell-main", 194) == 1 + assert cobertura.hitsPerLine(dom, "shell-main", 195) is None + assert cobertura.hitsPerLine(dom, "shell-main", 196) is None + assert cobertura.hitsPerLine(dom, "shell-main", 197) is None + + assert cobertura.hitsPerLine(dom, "shell-main", 199) == 1 + assert cobertura.hitsPerLine(dom, "shell-main", 200) is None + assert cobertura.hitsPerLine(dom, "shell-main", 201) is None + assert cobertura.hitsPerLine(dom, "shell-main", 202) is None + + +class bash_subshell_function(libkcov.TestCase): + def runTest(self): + rv, o = self.do( + self.kcov + " " + self.outbase + "/kcov " + self.sources + "/tests/bash/subshell.sh" + ) + + dom = cobertura.parseFile(self.outbase + "/kcov/subshell.sh/cobertura.xml") + + assert cobertura.hitsPerLine(dom, "subshell.sh", 12) is None + assert cobertura.hitsPerLine(dom, "subshell.sh", 13) == 1 + assert cobertura.hitsPerLine(dom, "subshell.sh", 14) is None + + assert cobertura.hitsPerLine(dom, "subshell.sh", 16) == 1