powershell批处理——io校验
在刷题时,时常回想,OJ平台是如何校验竞赛队员提交的代码的,OJ平台并不看代码,而是使用“黑盒测试”,用测试数据来验证。对于每题,都事先设定了很多组输入数据(datain)和输出数据(dataout),OJ主要是看输入datain,看产生的输出是否与dataout一致。
如果需要一次性知道自己的所有测试输入数据是否能得到正确输出,一个一个测试就太慢了,批处理操作就能很好解决这个问题。本篇文章主要介绍一下这个ioCode
小项目,主要用于批处理校验输入输出,搭建本地的评测平台。
项目目录结构
- input目录:存放输入数据文件,以
.in
后缀结尾 - output目录:存放输出数据文件,以
.out
后缀结尾,每个输出的文件名与对应的输入的文件名相同 - start.ps1:编写的脚本文件
start.ps1源代码:
function ioCheck{param($content, #程序输出内容$answer #输出的答案内容)$cnt = $answer.lengthif($content.length -ne $cnt){return 0 #内容行数不等,直接返回0}for($i=0;$i -lt $cnt;$i++){if($answer[$i] -ne $content[$i]){return 0} }return 1
}function ioCode{param([string]$command,[string]$inPath = './input',[string]$outPath = './output')$list = New-Object System.Collections.ArrayList #创建正确输出的文件名集合$inFiles = Get-ChildItem -Path $inPath -Filter *.in #获取输入文件集$len = $inFiles.length$cnt = 0 foreach($file in $inFiles){try {$fullOut = cmd.exe /c "$command < $($file.fullName)" #获取程序实际输出内容$answerPath = Join-Path -Path $outPath -ChildPath ($file.BaseName + '.out')$answer = Get-Content -Path $answerPath #获取该输入文件的对应输出文件的内容if(ioCheck $fullOut $answer){$list.add($file.Name) | Out-Null #Out-Null表示丢弃输出$cnt++}}catch {Write-Host "处理文件 $($file.Name) 时出现错误: $_"}}Write-Host "正确输出 $cnt/$len:"return @{CorrectCount = $cntTotalCount = $lenCorrectFiles = $list}
}
首先测试输入两个数,看能否成功输出两数之和
在input目录中创建三个文件分别为001.in
,002.in
,003.in
内容分别为
001.in
3 4
002.in
35749 47985
003.in
544 6755
对应的在output目录创建三个同名的.out
文件,分别为001.out
,002.out
,003.out
内容就是对应.in
文件中两个输入数据的相加的结果。
使用
编写好测试用例,就是可以测试我们写好的代码了,这里不仅可以测试C/C++生成的.exe
可执行文件,还可以测试java生成的.class
可执行字节码文件(前提是电脑具备java环境)。
测试.exe
文件
在当前目录下准备一个test.cpp
文件,代码如下:
#include<iostream>
using namespace std;
int main()
{int a, b;cin >> a >> b;cout <<a<<"+"<<b <<"=" << a + b;return 0;
}
将其编译为可执行文件test.exe
:
g++ -o test.exe test.cpp
在当前目录下打开powershell控制台
- 通过点加载start.ps1文件
. './start.ps1'
- 输入命令
ioCode {command} {inPath} {outPath}
,command为可执行命令,inPath为输入文件目录(默认为当前目录的input目录),outPath为输出答案文件目录(默认为当前目录的output目录)
ioCode test.exe
示例:
控制台输出显示我们的三个测试用例都通过了。
测试可执行.class
文件
在当前目录下准备一个Main.java
文件,代码如下:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int a = scanner.nextInt();int b = scanner.nextInt();System.out.println(a+b);}
}
将其编译为可执行文件Main.class
:
javac Main.java
将其编译为可执行文件test.exe
:
g++ -o test.exe test.cpp
在当前目录下打开powershell控制台
- 通过点加载start.ps1文件
. './start.ps1'
- 输入命令
ioCode {command} {inPath} {outPath}
,command为可执行命令,inPath为输入文件目录(默认为当前目录的input目录),outPath为输出答案文件目录(默认为当前目录的output目录)
ioCode 'java Main' #注意java Main是一个完整的命令,中间带有空格,需要用引号引起来
示例:
以上就是这个小项目的内容,通过ioCode
可以批处理测试多个输入输出用例,并能清晰的看到哪些输入文件正确输出方便DeBug。
后面我打算继续优化一下,主要包括以下内容
- 快速构造输入,输出数据。
- 对于不正确的输出(与给定的输出文件不匹配),能清晰地指出出第一个不同的地方。
- 显示批处理执行耗时
更多优化点或不足的地方,期待指教。