/* +----------------------------------------------------------------------+ | HipHop for PHP | +----------------------------------------------------------------------+ | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) | | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ #include "hphp/runtime/base/code_coverage.h" #include "hphp/runtime/base/complex_types.h" #include "hphp/runtime/base/execution_context.h" #include "hphp/util/logger.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// /* * The function below will be called by the interpreter on each * evaluated expression when running hhvm with: * $ hhvm -v Eval.RecordCodeCoverage=1 * * The (line0, line1) pair is supposed to represent the start and end * of an evaluated expression. One should normally increment the line * usage counters for all the lines between line0 and line1 but certain * constructs like including a file, eval-ing a string, or even * executing a for loop do not have a good value for line1. * * Indeed on this toy cover.php file: * * line1) { return; } Logger::Verbose("%s, (%d, %d)\n", filename, line0, line1); CodeCoverageMap::iterator iter = m_hits.find(filename); if (iter == m_hits.end()) { vector &lines = m_hits[filename]; lines.resize(line1 + 1); for (int i = line0; i <= line0 /* should be line1 one day */; i++) { lines[i] = 1; } } else { vector &lines = iter->second; if ((int)lines.size() < line1 + 1) { lines.resize(line1 + 1); } for (int i = line0; i <= line0 /* should be line1 one day */; i++) { ++lines[i]; } } } Array CodeCoverage::Report() { Array ret = Array::Create(); for (CodeCoverageMap::const_iterator iter = m_hits.begin(); iter != m_hits.end(); ++iter) { const vector &lines = iter->second; Array tmp = Array::Create(); for (int i = 1; i < (int)lines.size(); i++) { if (lines[i]) { tmp.set(i, Variant((int64_t)lines[i])); } } ret.set(String(iter->first), Variant(tmp)); } return ret; } void CodeCoverage::Report(const std::string &filename) { std::ofstream f(filename.c_str()); if (!f) { Logger::Error("unable to open %s", filename.c_str()); return; } f << "{\n"; for (CodeCoverageMap::const_iterator iter = m_hits.begin(); iter != m_hits.end();) { const vector &lines = iter->second; f << "\"" << iter->first << "\": ["; int count = lines.size(); for (int i = 0 /* not 1 */; i < count; i++) { f << lines[i]; if (i < count - 1) { f << ","; } } f << "]"; if (++iter != m_hits.end()) { f << ","; } f << "\n"; } f << "}\n"; f.close(); } void CodeCoverage::Reset() { m_hits.clear(); g_vmContext->resetCoverageCounters(); } /////////////////////////////////////////////////////////////////////////////// }