乐趣区

关于编译:南京大学编译实验-Lab-3-自动测试脚本NJU编译原理课程-C-语言实验的-irsimpyc-虚拟机小程序自动化执行

南京大学编译试验 Lab 3 自动测试脚本

文章版权属于 法华寺中班小屁孩 @ 博客园(也就是我),未经作者容许,禁止转载。
文章地址 https://www.cnblogs.com/stupi…
GitHub: StupidPanther

本文将贴出用于编译试验 3 的自动测试脚本源码。

波及版权,本文将不会提供 irsim.pyc 虚拟机小程序和任何官网测试样例。

脚本的运行须要配置 python3 等环境,置信对于大家来说不是问题,后文也会对环境配置给予探讨。

OK,进入正题。首先明确,本脚本判断测试是否正确的规范 执行你的编译器编译失去的 IR 程序,是否能产生预期的输入

本地文件构造

应用脚本自动测试,须要依照如下所示组织本地文件构造:

.
├── auto_run_irsim.py   # 与运行 irsim.pyc 相干的脚本
├── run.py              # 自动化测试脚本,即你要执行的脚本
├── irsim.pyc -> /home/me/Compiler/irsim/irsim.pyc  # 链接到 irsim.pyc 的软链接
├── expects             # 你冀望的输入(即执行 C -- 编译器输入的 IR 文件所冀望的输入)│   └── doc.1.1.expect
├── inputs              # 测试样例(用 C -- 语言编写)│   └── doc.1.1.cmm
├── irs                 # 编译测试样例失去的 IR 文件(该文件夹无需事后新建)├── outputs             # 执行 IR 程序的理论输入(该文件夹无需事后新建)└── texts               # 执行 IR 程序所对应的 stdin(即执行 IR 程序时本须要手工输出的数据)└── doc.1.1.text

run.pyauto_run_irsim.py 的代码将在稍后贴出。接下来将会解释 inputstextsexpects 文件夹中的文件应如何筹备(即如何筹备测试样例)。

筹备测试样例

须要筹备好 inputstextsexpects 文件夹。

inputs文件夹:C– 语言源程序

无需多说,C– 语言源程序合乎试验手册要求即可。须要留神,inputs文件夹中的文件名(不含后缀)须要与 textsexpects文件夹中对应的文件 雷同,正如上文中的文件结构图所示。

上面给出一个示例:doc.1.1.cmm

int main()
{
    int a;
    int b;
    read(a);
    b = a + 1;
    write(b);
    return 0;
}

texts文件夹:执行 IR 程序须要的 stdin 内容(即本需手工输出的数据)

C– 语言源程序中如果调用了 read 函数,那么,在执行其对应的 IR 时,须要手工输出数据,这里将本应手工输出的数据写在 texts 文件夹中后缀为 .text 的文件中。

留神:每个数据 均以 换行符完结,文件的后缀 必须 .text

上面给出一个示例:doc.1.1.text,这个示例恰对应于上文中的doc.1.1.cmm,留神数字 100 后有一个换行符。

100

expects文件夹:执行 IR 程序冀望取得的输入

脚本会主动执行你的 C – 编译器,并将生成的 IR 程序存于 irs 文件夹中;之后,脚本主动运行 irsim.qyc 虚拟机小程序,应用其执行刚刚生成的 IR 程序,并将输入后果写入 outputs 文件夹中。

你要做的,是将你所冀望的输入后果写入 expects 文件夹中以 .expect 为结尾的文件中。

留神:文件的完结 没有 换行符,文件的后缀 必须 .expect

上面给出一个示例:doc.1.1.expect,这个示例恰对应于上文中的源程序和 stdin。依据源程序的语义,应冀望输入整数 101,留神数字 101 后没有换行符。

101

脚本源代码

上面的脚本由 python3 书写。

脚本run.py

留神:对于脚本,有惟一一处 必要 的批改,在第 42 行,详见正文。

#!/usr/bin/python3

# Author: stupidpanther @ GitHub

import time
import os
import re
import sys
import auto_run_irsim

ESC_RED="\033[31m"
ESC_GREEN="\033[32m"
ESC_CYAN="\033[36m"
ESC_END="\033[0m"

def RunParser(executable, input_file_full_name, ir_file_full_name, output_file_full_name):
    os.system("touch" + output_file_full_name)
    os.system(executable + "" + input_file_full_name +" "+ ir_file_full_name +" > " + output_file_full_name)
    f = open(output_file_full_name)
    output_text = f.read()
    f.close()
    if output_text == '':
        return 0
    else:
        return -1

def main():
    try:
        print(ESC_CYAN + "script running..." + ESC_END)

        start_time = time.asctime(time.localtime(time.time()))

        num_total_files=0
        num_pass_files=0

        # mission start
        #

        output_dir_name = "./outputs/"
        ir_dir_name = "./irs/"
        input_text_dir_name = "./texts/"
        input_dir_name  = "./inputs/"
        expect_dir_name = "./expects/"
        executable = "../cc" # 请将双引号内批改为你的编译器的相对地址 或 绝对于本文件夹的绝对地址
        irsim = "./irsim.pyc"
        output_file_suffix = ".output"
        ir_file_suffix = ".ir"
        input_text_suffix = ".text"
        expect_file_suffix = ".expect"

        # make ir/output dir
        if not os.path.exists(ir_dir_name):
            os.makedirs(ir_dir_name)
        if not os.path.exists(output_dir_name):
            os.makedirs(output_dir_name)

        # traverse input files
        for root_dir, dirs, files in os.walk(input_dir_name):
            for input_file_name in files:
                num_total_files += 1
                # === process an input file ===
                file_pass = True     # is this file pass
                input_file_full_name = root_dir + input_file_name
                input_file_pure_name = (re.findall(r"(.+)\.", input_file_name))[0]
                output_file_full_name = output_dir_name + input_file_pure_name + output_file_suffix
                ir_file_full_name = ir_dir_name + input_file_pure_name + ir_file_suffix
                input_text_file_full_name = input_text_dir_name + input_file_pure_name + input_text_suffix
                expect_file_full_name = expect_dir_name + input_file_pure_name + expect_file_suffix
                # get output
                ### ====== STEP I  ====== 
                run_rst = 0
                compile_rst = 0
                compile_rst = RunParser(executable, input_file_full_name, ir_file_full_name, output_file_full_name)
                if compile_rst == 0:
                    ### == STEP II ====== 
                    auto_run_irsim.RunIRSim()
                    f = open(input_text_file_full_name)
                    input_text = f.read()
                    f.close()
                    input_text_lines = input_text.split("\n")
                    input_text_lines.remove('')
                    run_rst = auto_run_irsim.RunTestCase(ir_file_full_name, output_file_full_name, input_text_lines)
                    auto_run_irsim.StopIRSim()
                ### ====================
                if run_rst != 0:
                    file_pass = False
                else:
                    if compile_rst != 0:
                        print(input_file_full_name, "Compile error, ignore.")
                    # read output file
                    f = open(output_file_full_name)
                    my_lines = f.readlines()
                    f.close()
                    # read expect file
                    f = open(expect_file_full_name)
                    official_lines = f.readlines()
                    f.close
                    # compare
                    if my_lines == official_lines:
                        file_pass = True
                    else:
                        file_pass = False
                # print result
                if file_pass == True:
                    num_pass_files += 1
                    print(ESC_GREEN + "PASS" + input_file_full_name + ESC_END)
                else:
                    print(ESC_RED + "FAIL" + input_file_full_name + ESC_END, file=sys.stderr)
                    print(ESC_CYAN + ">>>" + expect_file_full_name + ">>>" + ESC_END)
                    os.system("cat" + expect_file_full_name)
                    print("")
                    print(ESC_CYAN + ">>>" + output_file_full_name + ">>>" + ESC_END)
                    os.system("cat" + output_file_full_name)
                    print("")
                    
        #
        # mission complete

        end_time = time.asctime(time.localtime(time.time()))

        print("------")
        print("number of total files:", num_total_files)
        print("number of pass  files:", num_pass_files)
        print("------")
        print(ESC_CYAN + "start at" + start_time + ESC_END)
        print(ESC_CYAN + "end   at" + end_time   + ESC_END)

        if num_total_files == num_pass_files:
            sys.exit(0)
        else:
            sys.exit(-1)
    except Exception as excep:
        print(excep, file=sys.stderr)
        sys.exit(-2)

if __name__ == "__main__":
    main()

脚本auto_run_irsim.py

这个脚本无需批改任何内容。

#!/usr/bin/python3

# Author: stupidpanther @ GitHub

import pyautogui
import os
import time
import gi
gi.require_version('Wnck', '3.0')
from gi.repository import Wnck

def RunIRSim():
    os.system("python ./irsim.pyc &")
    time.sleep(0.75)

def StopIRSim():
    pyautogui.hotkey('alt', 'f4')

def RunTestCase(testcase_name, output_name, input_text_lines):
    pyautogui.hotkey('ctrl', 'o')
    time.sleep(0.1)
    pyautogui.typewrite(testcase_name)
    pyautogui.press('enter')
    time.sleep(0.05)
    # run
    pyautogui.press('f5')
    for line in input_text_lines: # enter input
        pyautogui.typewrite(line) 
        pyautogui.press('enter')
    time.sleep(0.1)
    # check if successful
    src = Wnck.Screen.get_default()
    src.force_update()
    window_title = src.get_active_window().get_name()
    src = None
    Wnck.shutdown()
    pyautogui.press('enter')
    if window_title != "Finish":
        return -1
    else:
        # scroll
        pyautogui.moveTo(836, 533)
        pyautogui.dragTo(836, 350)
        # select
        pyautogui.moveTo(492, 400)
        pyautogui.mouseDown()
        pyautogui.moveTo(855, 626)
        time.sleep(1.2)
        pyautogui.mouseUp()
        pyautogui.hotkey('ctrl', 'c')
        os.system("xclip -o >" + output_name)
        return 0

脚本应用

首先赋予脚本执行权限:

chmod +x ./run.py
chmod +x ./auto_run_irsim.py

要自动化执行测试样例,在当前目录下,执行以下命令:(留神,脚本运行期间,不要 应用鼠标、不要 应用键盘)

./run.py

在我的本地环境,失去以下输入:

script running...
PASS ./inputs/doc.2.2.cmm
PASS ./inputs/doc.1.1.cmm
PASS ./inputs/doc.3.1.cmm
PASS ./inputs/doc.2.1.cmm
PASS ./inputs/doc.1.3.cmm
PASS ./inputs/doc.2.3.cmm
PASS ./inputs/doc.4.1.cmm
PASS ./inputs/doc.1.2.cmm
------
number of total files:  8
number of pass  files:  8
------
start at Thu May  5 18:24:56 2022
end   at Thu May  5 18:25:28 2022

环境依赖

最初,如你所见,脚本中应用了如 pyAutoGUI 等第三方包。尽管装置它们并不难,但在这里多说几句也不是好事。

再次强调,本脚本依赖于 Python 3,我的本地环境是:

me@ubuntu:~$ uname -a
Linux ubuntu 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
me@ubuntu:~$ python3 --version
Python 3.5.2
me@ubuntu:~$ python3 -m pip --version
pip 20.3.4 from /home/me/.local/lib/python3.5/site-packages/pip (python 3.5)

另外,脚本须要装置 包含但不限于 以下依赖:

pyAutoGUIWnck

对于 pyAutoGUI,有人并不倡议在 Ubuntu 16.04 上应用,但限于试验要求,不得不作出退让。我的确留神到,在装置pyAutoGUI 时,有些其依赖没有装置胜利;不过,本着“能用就是好用”的准则,通过实际,这并没有影响我实现这个自动化测试脚本。

结语

写这个脚本的次要目标是自用,而不是面向用户体验,所以用起来有些繁琐在劫难逃。

祝我和大家试验欢快。

退出移动版