CSES - Brutetestaus

Brutetestaus

Brutetesterin voi kirjoittaa monella tavalla, mutta ainakin jokin tapa on hyvä osata rutiinilla.

Alla esimerkki C++-brutetestaajan rungosta. Varsinainen koodi on tiedostossa koodi.cpp käännettynä tiedostoon koodi, bruteratkaisu on tiedostossa brute.cpp, käännettynä brute.

#include <bits/stdc++.h>
using namespace std;

int main() {
  while (true) {
    // Generoi sattumanvarainen syöte tiedostoon
    ofstream f("syote");
    int n = rand()%10+1;
    f << n << endl;
    f.close();

    // Aja molemmat koodit
    system("./brute < syote > out_brute");
    system("./koodi < syote > out_koodi");

    // Vertaa tulosteita
    if (system("diff -b out_brute out_koodi")) {
      cout << "Virhe löytyi!" << endl;
      break;
    }
  }
}

Komento diff lipulla -b vertailee kätevästi tulosteita välittämättä ylimääräisistä välilyönneistä, kuten kisajärjestelmätkin.

Välillä ei ole tarkoituskaan, että tulosteet ovat identtisiä, vaan oikeellisuus pitää tarkastaa jollain toisella tavalla. Tällöin tulosteet voidaan lukea käyttäen ifstream-virtoja:

    // Vertaa tulosteiden ensimmäistä lukua
    ifstream fa("out_brute"), fb("out_koodi");
    long a, b;
    fa >> a;
    fb >> b;
    if (a != b) {
      cout << "Virhe löytyi!" << endl;
      break;
    }

Jos ja kun brutetesteri löytää virheen, pysähtymisen jälkeen tiedostot syote, out_brute, out_koodi vastaavat sitä syötettä, jolla virhe löytyi. Koodia voi siis ajaa samalla syötteellä uudestaan. Voi olla hyödyllistä ottaa syöte talteen, ettei vahingossa ylikirjoita sitä myöhemmin.

cp syote syote_rikki
./koodi < syote_rikki

Syötettä voi myös käyttää GDB:ssä (muista oikeat käännösliput, ks. GDB-ohje):

gdb koodi
run < syote_rikki

Toinen hyvä kieli brutetesterin toteuttamisielle on Python. Alla esimerkki Python-pohjaisesta testeristä:

import os, random

while True:
    with open("input", "w") as f:
        n = random.randint(1, 10)

        f.write(f"{n}\n")

    os.system("./koodi < input > out_koodi")
    os.system("./brute < input > out_brute")

    if os.system("diff -b out_koodi out_brute"):
        print(":(")
        exit()