[PYTHON] [Atcoder] [C ++] Ich habe ein Testautomatisierungstool erstellt, das während des Wettbewerbs verwendet werden kann

Ich mache Atcoder (Wettbewerbsprogrammierung) als Hobby, aber es war in letzter Zeit träge. Ich dachte, es wäre schön, die Testarbeit während des Wettbewerbs zu automatisieren. Ich habe ein Testautomatisierungstool mit Python erstellt.

Einführung

Im Folgenden finden Sie einige der vielseitigeren Tools als die, die ich in diesem Artikel vorgestellt habe.

Bitte vergleichen Sie auch die oben genannten, wenn Sie es verwenden.

1. Was wurde erreicht?

Quellcode https://github.com/tks3210/autoJudge

** Betriebsumgebung **

2. Betriebsbeispiel

2.1 Automatisierter Test

>python autojudge.py [contest_name] [quest] Wenn Sie den Wettbewerbsnamen (abc143) und den Fragennamen (abc143_a) wie in ↑ angegeben angeben, Es wird automatisch erstellt, erhält Beispiel-Eingabe- / Ausgabedaten und testet sie. Ich habe auch versucht, eine Atmosphäre mit der ursprünglichen Familie zu schaffen. AC__.png Die obigen drei Testfälle sind https://atcoder.jp/contests/abc143/tasks/abc143_a Es wird automatisch aus dem Eingabe- und Ausgabebeispiel von erhalten.

Ich kann den Server von Atcoder nicht mit meinen eigenen Tests belästigen Der Zugriff ist für jedes Problem einmalig. (Der erfasste Testfall wird lokal gespeichert, damit in den nächsten und nachfolgenden Tests darauf verwiesen wird.)

2.2 Falsch positiv

Wenn Sie den falschen Code schreiben, werden Sie darauf hingewiesen, dass er falsch ist.

** Im Falle von WA (falsche Antwort) ** WA__.png ** Bei TLE (Berechnungszeit abgelaufen) ** Wenn in der aktuellen Einstellung ** 2 Sekunden ** überschritten werden, bis das Ergebnis ausgegeben wird, wird es als TLE behandelt. Selbst wenn Sie in einer Endlosschleife laufen, wird diese in ca. 3 Sekunden unterbrochen und der nächste Test durchgeführt. TLE__.png ** Im Falle von CE (Kompilierungsfehler) ** Es spielt keine Rolle, ob es überhaupt nicht kompiliert wird, also endet es ohne zu testen. CE__.png

2.3 Automatische Authentifizierung

Wenn Sie diesen Test während des Wettbewerbs ausführen, können Sie die Fragenseite nicht abrufen, ohne sich anzumelden. Durch Einstellen des Benutzernamens / Passworts usw. mit der Option -i werden die automatische Authentifizierung und die Testausführung während des Wettbewerbs aktiviert.

>python autojudge.py abc143 abc143_d -i
Atcoder Username:tks_fj * Benutzername des Atcoder-Kontos
Atcoder Password:******** Passwort des Atcoder-Kontos
Src Directory(Ex. ./aaa/abc140/abc140.cpp => input "./aaa"):../../02_contest
Judging abc143/abc143_d...
testcase 1: AC
testcase 2: AC
testcase 3: AC
result: AC

** Diese Einstellungsinformationen werden in der lokalen Einstellungsdatei (settings.conf) gespeichert, sodass diese Arbeit nur einmal ausgeführt werden kann. ** **. (Diese Arbeit kann auch durch direktes Umschreiben der Einstellungsdatei ausgeführt werden.)

2.4 Testfall hinzugefügt

Sie können auch interaktiv neue Testfälle hinzufügen Um die Eingabe und Ausgabe mehrerer Zeilen zu unterstützen, wird zum Beenden "Beenden" + Eingabetaste verwendet.

(Eingang:20 7 Ausgabe:Addiere 6)
>python autojudge.py abc143 abc143_a -a
type test input(exit by "quit")
20 7
quit
type test output(exit by "quit")
6
quit

Wenn Sie es erneut testen, wird es zu testcase4 hinzugefügt.

>python autojudge.py abc143 abc143_a
Judging abc143/abc143_a...
testcase 1: AC
testcase 2: AC
testcase 3: AC
testcase 4: AC
result: AC

** Informationen zu den Grundeinstellungen finden Sie unter Auto Judge: Initial Settings oder im nächsten Kapitel. ** **.

3. Design und Implementierung

Ich werde auch das Design und die Implementierung im Inneren vorstellen, die auch als Memorandum dienen.

3.1 Verzeichnisstruktur

Die folgenden Artefakte werden in einem Repository namens ** autoJudge ** verwaltet.

  • ** autojudge.py (Hauptteil des Programms) **
  • ** settings.conf (Einstellungsdatei) **
  • ** Testfall / (Testfall, zur Laufzeit generiert) **

Es wird davon ausgegangen, dass ** autoJudge ** in dem Verzeichnis geklont wird, in dem der zu testende Quellcode (.cpp) gespeichert ist. Es wird empfohlen, mit der folgenden Verzeichnisstruktur und Namenskonvention zu arbeiten. (Aber es funktioniert auch, wenn es nicht ↓ ist (siehe 4. Zusätzliche Option -p))

.
├── autoJudge * Das diesmal erstellte Ergebnis
│   ├── setting.conf * Datei einstellen
│   ├── autojudge.py * Programmkörper
│ ├ Testfall * Liste der Testfälle(Wird während des Tests generiert)
│   │   ├── abc142@abc142_a.txt
│   │   └── abc143@abc143_a.txt 
│   └── design.pu * Klassendiagramm
├── abc142 * Name des Wettbewerbs
│   ├── abc142_a.cpp * Problemname.cpp
│   ├── abc142_b.cpp
│   ├── abc142_c.cpp
│   ├── abc142_d.cpp
│   ├── abc142_e.cpp
│   └── abc142_f.cpp
├── abc143
:

3.2 Einstellungsdatei (settings.conf)

Dies ist eine Einstellungsdatei, die zur Authentifizierung und Suche nach dem Speicherort der Quelle verwendet wird.

setting.conf


username:tks_fj
password:*******
srcpath:../
  • Geben Sie den Benutzernamen / das Passwort unter Benutzername / Passwort ein (erforderlich beim Anmelden).
  • Beschreiben Sie den relativen Pfad von autoJudge.py zu "Wettbewerbsname / Problemname" in srcpath

Es kann mit der in ** 2.3 Automatische Authentifizierung ** eingeführten Option -i eingestellt werden, aber es ist natürlich in Ordnung, direkt neu zu schreiben.

3.3 Programmkörper (autojudge.py)

3.3.1 Klasse

Das Programm besteht aus den folgenden zwei Klassen.

  • ** ManageTestCases **: Testfälle abrufen und verwalten
  • ** ExecuteTestCases **: Führen Sie Tests basierend auf Testfällen aus autojudge.png

3.3.2 ManageTestCases: Testverwaltungsklasse

  • ** RegisterUser (): Bearbeiten der Einstellungsdatei (settings.conf) **
  • Aktualisieren Sie die Einstellungsdatei, indem Sie den Benutzernamen, das Kennwort und den Quellcodepfad von der Standardeingabe erhalten.

autojudge.py


    def RegisterUser(self):
        """Benutzereinstellungen(Erstes Mal)"""

        print("Atcoder Username:", end="")
        username = input().rstrip('\r\n')
        print("Atcoder Password:", end="")
        password = input().rstrip('\r\n')
        print("Src Directory(Ex. ./aaa/abc140/abc140.cpp => input \"./aaa\"):", end="")
        srcpath = input().rstrip('\r\n')

        with open(CONF_FILE, "w") as f:
            f.write("username:" + username + "\n")
            f.write("password:" + password + "\n")
            f.write("srcpath:" + srcpath + "\n")
  • ** GetTestCases (): Testfälle abrufen **
  • Generieren Sie den URI der Fragenseite bei der ersten Ausführung aus dem Wettbewerbsnamen / Fragennamen, rufen Sie den Testfall ab und zeichnen Sie ihn in der Datei auf
  • Lesen Sie die Datei und erhalten Sie den Testfall für die zweite und nachfolgende Ausführung.
  • Gibt Testfälle und Informationen zu Wettbewerbsnamen / Fragennamen zurück (testinfo).

autojudge.py


    def GetTestCases(self, test_name, islogin = False):
        """Ruft einen Testfall aus dem angegebenen Problemnamen ab und gibt eine Liste zurück"""

        self.__UpdateConf()
        file_name = self.contest + "@" + test_name + ".txt"
        testinfo = [{"contest":self.contest, "testname":test_name}]
        #Schaben Sie nicht die Erfassung derselben Informationen ab, um die Serverlast zu verringern
        if file_name in os.listdir(TESTCASES_PATH):
            testcases = self.__ReadFile(file_name)
        else:
            testcases = self.__ScrapePage(test_name, islogin)
            self.__WriteFile(file_name, testcases)
        return testinfo + testcases
  • ** AddTestCases (): Testfälle hinzufügen **
  • Fügen Sie interaktiv Testfälle (Eingabe, Ausgabe) für das angegebene Problem hinzu.
  • Akzeptieren Sie mehrzeilige Testfälle (Beenden mit "Beenden" + Eingabetaste)

autojudge.py


    def AddTestCases(self, test_name):
        """Fügen Sie dem erfassten Testfall Ihren eigenen Testfall hinzu"""

        self.__UpdateConf()
        testcase = {}
        print("type test input(exit by \"quit\")")
        testcase["input"] = ""
        while(1):
            line = input()
            if (line == "quit"):
                break;
            testcase["input"] += line + "\n"
        print("type test output(exit by \"quit\")")
        testcase["output"] = ""
        while(1):
            line = input()
            if (line == "quit"):
                break;
            testcase["output"] += line + "\n"
        file_name = self.contest + "@" + test_name + ".txt"
        if file_name in os.listdir(TESTCASES_PATH):
            testcases = self.__ReadFile(file_name)
        testcases.append(testcase)
        self.__WriteFile(file_name, testcases)

3.3.3 ExecuteTestCases: Testausführungsklasse

  • ** Execute (): Testfall ausführen **
  • Wenn der Build (\ _ \ _ Build) erfolgreich ist, wird er ausgeführt (\ _ \ _ Run) und schließlich wird das Ergebnis ausgegeben (\ _ \ _ Result) (AC, WA, TLE).
  • Wenn der relative Pfad der Quelle nicht festgelegt ist, wird er automatisch aus der Einstellungsdatei generiert.
  • __Run Startet einen untergeordneten Prozess in Run und erkennt TLE durch Messen der Ausführungszeit.

autojudge.py


    def Execute(self, srcpath = ""):
        """Führen Sie den Test aus"""

        print(YELLOW + "Judging " + self.testinfo["contest"] + "/" + self.testinfo["testname"] + "..." + COLORRESET)
        if (srcpath == ""):
            srcpath = self.__GetPath()
        self.__Build(srcpath)
        if (self.result["build"] == 0):
            self.__Run()
        self.__Result()

3.4 Testfall (Testfall /)

  • Bei der ersten Ausführung des Tests wird unter dem Testfall eine Textdatei generiert. (Wettbewerbsname @ Problemname.txt)
  • Das Format ist wie folgt

abc143@abc143_a.txt


[test case 0]
---input---
12 4
---output---
4
---fin---
[test case 1]
---input---
20 15
---output---
0
---fin---

3.5 Ergebnisanzeige

  • Zeigen Sie die Ergebnisse und Gesamtergebnisse für jeden Testfall an.
  • AC wird grün und WA, TLE, CE gelb angezeigt.
  • WA (Fehler im Ergebnis) gibt Vorhersage und Ergebnis aus. WA__.png

4. Ergänzung

4.1 In Bezug auf die Python-Umgebung

Folgende Module sind erforderlich. Sie können es sofort mit pip, pip3, conda usw. einfügen.

pip3 install requests
pip3 install bs4, lxml

4.2 Optionsliste

  • Testfall mit -a hinzufügen
  • Grundeinstellung mit -i (Einstellungsdatei aktualisieren)
  • Geben Sie den Quellcodepfad direkt mit -p an
>python autojudge.py --help
usage: autojudge.py [-h] [-p PATH] [-a] [-i] contest_name question

positional arguments:
  contest_name          set contest name(ex. abc143)
  question              set question name(ex. abc143_a)

optional arguments:
  -h, --help            show this help message and exit
  -p PATH, --path PATH  set path of source code
  -a, --addtest         add testcase
  -i, --init            set configuration

4.3 Bezüglich der Pfadangabe (-p)

Wenn die Verzeichnisstruktur des Quellcodes nicht "3.1 Verzeichnisstruktur" ist (Zum Beispiel in den folgenden Fällen)

.
├── 02_contest
│   ├── abc143
│   │   ├── abc143_a.cpp
│   │   ├── abc143_b.cpp
│   │   └── abc143_c.cpp
├── 04_autotest
│   ├── autoJudge
│   │   ├── README.md
│   │   ├── autoJudge.py
│   │   ├── autojudge.pu
│   │   ├── setting.conf
│   │   └── testcase

Sie können den Speicherort des Quellcodes direkt mit der Option -p angeben.

>python autojudge.py abc143 abc143_a -p ../../02_contest/abc143/abc143_a.cpp
Judging abc143/abc143_a...
testcase 1: AC
testcase 2: AC
testcase 3: AC
testcase 4: AC
result: AC

4.4 Bekannte Probleme

  • Es kann bei der ersten Ausführung zu TLE werden (einschließlich Scraping-Zeit ??)
  • ** Nicht kompatibel mit dem Problem, dass die richtige Antwort (AC) unter einem bestimmten Fehler liegt **
  • Ist die Genauigkeit der TLE-Beurteilung subtil?
  • PermissionError wird während TLE ausgegeben (nur Win10-Umgebung)
  • Nicht kompatibel mit Laufzeitfehler (RE)
  • Gelegentlich Fehler

5. Nachtrag

  • plantUML war gut (wurde verwendet, um ein Klassendiagramm zu erstellen)
  • BeutifulSoup war auch gut (für HTML-Analyse verwendet)
  • argperse ist ebenfalls leicht gebogen (wird für die optionale Analyse verwendet)
  • Es gab viele Pioniere
    • https://github.com/kyuridenamida/atcoder-tools
    • https://github.com/nodchip/OnlineJudgeHelper
  • Ich möchte schnell blau werden

Recommended Posts