cocos2dx中对lua脚本进行覆盖率测试

原理很简单,利用debug.sethook可以得到代码执行情况,然后再用phpunit来生成html版本的覆盖率报告出来

直接上两个代码首先是CodeCoverage.lua

module("CodeCoverage", package.seeall)

local mResult = nil
local mRunninng = false
local mPrefix = nil
local mPrefixLen = 0

local function execCallback(event, line)
	if line == 0 or event ~= "line" or mResult == nil then
		return
	end

	local source = debug.getinfo(2, "S").source
	if mPrefixLen > 0 then
		local prefix = source:sub(1, mPrefixLen)
		if prefix ~= mPrefix then
			return
		end
		if mPrefix == "@" then
			source = source:sub(2)
		end
	end

	if mResult[source] == nil then
		mResult[source] = {
			[line] = 1
		}
	elseif mResult[source][line] == nil then
		mResult[source][line] = 1
	end
end

function start(prefix)
	if mRunning then
		return
	end

	debug.sethook(execCallback, 'l')
	mPrefix = prefix
	if mPrefix ~= nil then
		mPrefixLen = mPrefix:len()
	else
		mPrefixLen = 0
	end
	if mResult == nil then
		mResult = {}
	end
	mRunning = true
end

function stop(file)
	debug.sethook()
	mRunning = false
	if file ~= nil then
		save(file)
	end
end

function save(file)
	if mResult == nil then
		return false
	end
	local f = io.open(file,'w')
	for source, lines in pairs(mResult) do
		for line, count in pairs(lines) do
			f:write(string.format("%s %d %d\n", source, line, count))
		end
	end
	f:close()
	mResult = nil
	return true
end

接下来是生成覆盖率的php代码

define ( 'PREFIX', "/home/pirate/sgres/Resources/" );

function generate()
{

	$coverage = new PHP_CodeCoverage ();
	$dir = opendir ( COV_ROOT );
	if (empty ( $dir ))
	{
		echo COV_ROOT . " can't be opened, please check if it exists\n";
		return;
	}
	
	$arrCoverage = array ();
	$arrFile = array ();
	while ( true )
	{
		$file = readdir ( $dir );
		if (empty ( $file ))
		{
			break;
		}
		if ($file == '.' || $file == '..')
		{
			continue;
		}
		$file = COV_ROOT . '/' . $file;
		$arrFile [] = $file;
		$fh = fopen ( $file, 'r' );
		$arrData = array ();
		while ( ! feof ( $fh ) )
		{
			$line = fgets ( $fh );
			$arrLine = explode ( ' ', $line, 3 );
			if (count ( $arrLine ) != 3)
			{
				continue;
			}
			$source = $arrLine [0];
			$lineno = $arrLine [1];
			$flag = $arrLine [2];
			if (substr ( $line, 0, 1 ) != "/")
			{
				$source = PREFIX . $source;
			}
			if (! file_exists ( $source ))
			{
				continue;
			}
			$arrData [$source] [$lineno] = $flag;
		}
		fclose ( $fh );
		
		if (empty ( $arrCoverage ))
		{
			$arrCoverage = $arrData;
			continue;
		}
		
		foreach ( $arrData as $file => $arrLine )
		{
			if (! isset ( $arrCoverage [$file] ))
			{
				$arrCoverage [$file] = $arrLine;
				continue;
			}
			
			foreach ( $arrLine as $line => $flag )
			{
				if (! isset ( $arrCoverage [$file] [$line] ))
				{
					$arrCoverage [$file] [$line] = $flag;
					continue;
				}
				
				if ($arrCoverage [$file] [$line] < $flag)
				{
					$arrCoverage [$file] [$line] = $flag;
				}
			}
		}
	}
	
	if (count ( $arrFile ) > 1)
	{
		$time = intval ( microtime ( true ) * 1000 );
		$filename = COV_ROOT . '/' . $time . '.cov';
		$fh = fopen ( $filename, 'w+' );
		foreach ( $arrCoverage as $source => $arrLine )
		{
			foreach ( $arrLine as $line => $flag )
			{
				fprintf ( $fh, "%s %d %d\n", $source, $line, $flag );
			}
		}
		fclose ( $fh );
		
		foreach ( $arrFile as $file )
		{
			unlink ( $file );
		}
	}
	
	foreach ( $arrCoverage as $source => &$arrLine )
	{
		$fh = fopen ( $source, 'r' );
		$i = 0;
		$inFunc = false;
		$funcStart = 0;
		$funcEnd = 0;
		$inComment = false;
		$commentCount = 0;
		while ( ! feof ( $fh ) )
		{
			$i ++;
			$line = fgets ( $fh );
			$line = trim ( $line );
			
			// 过滤空行
			if ($line == "")
			{
				continue;
			}
			
			// 过滤未执行函数
			if (isset ( $arrLine [$i] ))
			{
				if (! $inFunc)
				{
					if (substr ( $line, 0, 9 ) == "function ")
					{
						$inFunc = true;
						$funcStart = $i;
					}
				}
				else
				{
					if (substr ( $line, 0, 3 ) == "end")
					{
						$funcEnd = $i;
						for($j = $funcStart; $j <= $funcEnd; $j ++)
						{
							$arrLine [$j] = - 1;
						}
					}
					$inFunc = false;
				}
			}
			else
			{
				// 过滤注释
				$prefix = substr ( $line, 0, 4 );
				if (! $inComment)
				{
					if ($prefix == '--[[')
					{
						$inComment = true;
						$commentCount = 1;
						continue;
					}
					
					if (substr ( $line, 0, 2 ) == "--")
					{
						continue;
					}
				}
				else
				{
					if ($prefix == '--[[')
					{
						$commentCount ++;
					}
					else if ($prefix == '--]]')
					{
						$commentCount --;
						if ($commentCount == 0)
						{
							$inComment = false;
						}
					}
					continue;
				}
				
				$arrLine [$i] = - 1;
			}
		}
		fclose ( $fh );
	}
	
	$coverage->append ( $arrCoverage, 'cov' );
	$generator = new PHP_CodeCoverage_Report_HTML ();
	$generator->process ( $coverage, COVERAGE_ROOT );
	echo sprintf ( "generate cov file in '%s' to '%s', done\n", COV_ROOT, FrameworkConfig::COVERAGE_ROOT );

}

generate ();

COV_ROOT是存放覆盖率文件的目录,COVERAGE_ROOT是生成html代码的目录,由于这段代码是从一个框架里摘出来的,不能直接运行,大家如果需要使用的话,需要稍微做些调整,加些require与define之类的东西

你可能感兴趣的:(cocos2dx中对lua脚本进行覆盖率测试)