wordcount程序实现与测试
GitHub地址
https://github.com/jiaxuansun/wordcount
PSP表格
PSP | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 5 |
·Estimate | 估计这个任务需要多少时间 | 10 | 5 |
Development | 开发 | 510 | 500 |
·Analysis | 需求分析 (包括学习新技术) | 40 | 30 |
·Design Spec | 生成设计文档 | 20 | 20 |
·Design Review | 设计复审 (和同事审核设计文档) | 10 | 10 |
·Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
·Design | 具体设计 | 30 | 30 |
·Coding | 具体编码 | 300 | 240 |
·Code Review | 代码复审 | 40 | 40 |
·Test | 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 70 | 80 |
·Test Report | 测试报告 | 30 | 40 |
·Size Measurement | 计算工作量 | 10 | 10 |
·Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 590 | 585 |
解题思路
对整体程序的功能需求进行划分如下:
-
参数分析功能:判断命令行的参数,保存所做的选项,并根据选项执行相应的命令,然后输出的结果
-
查找文件功能:查找输入的文件需要支持如"*.c"等简单匹配符,在有-s选项的情况下,需要在当前目录下递归查找文件
-
基本计数功能:实现课设基本功能要求的计算文件字符数、行数、单词数的功能
-
代码计数功能:实现课设扩展功能要求的计算文件代码行数、空行数、注释行数的功能
根据功能复杂程度选择Python语言完成作业
程序设计实现
根据分析结果将代码分为如下几个模块:
- 入口代码:设定所需要支持的参数内容
- main函数:查找目录下所有的目标文件,对每一个文件调用基本功能函数和扩展功能函数,并将结果返回;若选择-s选项,则递归查找当前目录下的各个目录
- wordcount函数:实现课设要求的基本功能
- codecount函数:实现课设要求的扩展功能
代码说明
入口和标准库的参数解析对象初始化:
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="word count")
parser.add_argument("-o", "--output", type=str, default="result.txt")
parser.add_argument("-c", "--bytes", action="store_true")
parser.add_argument("-w", "--words", action="store_true")
parser.add_argument("-l", "--lines", action="store_true")
parser.add_argument("-s", "--recursive", action="store_true")
parser.add_argument("-a", "--code", action="store_true")
parser.add_argument("-e", "--stoplist", type=str)
parser.add_argument("filename", type=str)
args = parser.parse_args()
result = main(args, os.getcwd())
print_result(args, result)
查找目录并根据不同的参数来调用不同的功能函数:
def main(args, rootpath):
result = []
filename = args.filename.replace("*", "\\w*")
if args.recursive:
for name in os.listdir(rootpath):
path = os.path.join(rootpath, name)
if os.path.isdir(path):
result += main(args, path)
elif re.findall(filename, name):
fd = open(path)
wc = wordcount(fd.read())
if args.stoplist:
fd.seek(0)
content = fd.read()
stoplist = open(args.stoplist)
stopchars = stoplist.read().split()
count = 0
for c in stopchars:
count += len(re.findall(c, content))
r["words"] -= count
stoplist.close()
if args.code:
fd.seek(0)
wc.update(codecount(fd))
wc["filename"] = name
result.append(wc)
fd.close()
else:
for name in os.listdir(rootpath):
path = os.path.join(rootpath, name)
if os.path.isdir(path):
pass
elif re.findall(filename, name):
fd = open(path)
wc = wordcount(fd.read())
if args.stoplist:
fd.seek(0)
content = fd.read()
stoplist = open(args.stoplist)
stopchars = stoplist.read().split()
count = 0
for c in stopchars:
count += len(re.findall(c, content))
r["words"] -= count
stoplist.close()
if args.code:
fd.seek(0)
wc.update(codecount(fd))
wc["filename"] = name
result.append(wc)
fd.close()
return result
基本功能实现:
def wordcount(content):
print(re.split(r"[\s,]+", content))
result = {
"words": len(re.split(r"[\s,]+", content))-1, # 单词数
"lines": len(content.split('\n'))-1, # 行数
"bytes": len(content)-1 # 字符数
}
return result
扩展功能实现
def codecount(fd):
codelines = 0
blanklines = 0
commentlines = 0
isComment = False
isString = False
isCode = False
for line in fd.readlines():
line = line.strip().replace('{', '').replace(
'}', '').replace(';', '') # 去掉{};以便计算空行
if not isComment and not line:
blanklines += 1
continue
if isComment:
commentlines += 1
elif line.replace('/', '').replace('*', ''):
codelines += 1
line = '\n'+line+'\n'
for i in range(1, len(line)):
if line[i] == '"' and line[i-1] != '\\':
isString = not isString
if not isString:
if line[i] == '/' and line[i+1] == '/' and not isComment:
if not line[:i].split():
blanklines += 1
commentlines += 1
break
if line[i] == '/' and line[i+1] == '*' and not isComment:
isComment = True
commentlines += 1
i += 1
if line[i] == '*' and line[i+1] == '/':
isComment = False
i += 1
result = {
"codelines": codelines,
"blanklines": blanklines,
"commentlines": commentlines
}
return result
测试设计过程
如何设计测试用例
测试时应重点考虑边界值以及特殊情况,使测试用例最大程度覆盖代码。
思想是使每一个判断语句都执行一遍,实现条件覆盖,尽量让每一个判断语句在是与否的情况下都能执行一遍,实现语句覆盖。
哪些地方会导致程序高风险
当输入文件内容为空或输入大于文件内容的边界时会导致程序高风险
测试代码设计
- test1.c
File write,name = new File(outputPath);
writename.createNe|wFile();
Buffe,redWriter out = new BufferedWrit,er(new FileWriter(writename));
out.close();
测试字符数统计
- test2.c
test()
{
File writename = new File(outputPath);
writename.createNewFile();
codeLine */
BufferedWriter out = new BufferedWriter(new FileWriter(writename));
// note line
out write(outputBuffer);
/* noteLine
/* noteLine
*/
/* noteLine */
/* noteLine
// noteLine
*/
out.flush();
out.close();
}
// noteLine
for(){}/* noteLine */
测试代码行数、注释行数、空行数统计
- test3.c
test()
{
File writename = new File(outputPath);
writename.createNewFile();
codeLine */
BufferedWriter out = new BufferedWriter(new FileWriter(writename));
// note line
out write(outputBuffer);
/* noteLine
/* noteLine
*/
/* noteLine */
/* noteLine
// noteLine
*/
out.flush();
out.close();
} // noteLine
for(){
}/* noteLine */
测试单词数、行数统计
- end.txt
for
new
out
- 测试递归查找文件:文件夹test1,其中有一个test3.c文件,选择-s选项测试即可
-测试命令:
wordcount.exe
wordcount.exe -c test1.c
wordcount.exe -w test3.c
wordcount.exe -l test3.c
wordcount.exe -a test2.c -o testout1.txt
wordcount.exe -s -w test3.c
wordcount.exe -w -e end.txt test2.c
wordcount.exe -a -w -e end.txt test1.c
wordcount.exe -l -w -a -c test2.c -o testout2.txt
wordcount.exe -l -w -a -c -s test3.c -o testout2.txt