Dzisiaj zajmiemy się przetestowaniem naszego algorytmu do wykrywania plagiatów w praktyce. Miejmy nadzieję, że to chociaż trochę zadziała 😉
Zestaw testowy
Musimy najpierw zacząć od przygotowania danych, na których będziemy testować naszą aplikacje.
Dzisiaj przygotujemy specjalnie spreparowane kody źródłowe i zobaczymy jak z nimi poradzi sobie nasza aplikacja.
Zacznijmy od stworzenia naszej wyjściowej klasy, która będzie zawierała kilka pól oraz metod.
public class ManyMethods {
private int a;
private int b;
private double c;
private double d;
private String e;
private String f;
public ManyMethods() {
a = 4;
b = 1;
c = -1.43;
d = 9.12;
e = "test";
f = "asdasd";
}
public void firstMethod() {
a = a + b;
}
public void secondMethod() {
a = a* a* a* a* a *a / 2*a;
b = (int) (b + a -8 + 9 * c);
}
public void thridMethod() {
c *= 123.432;
e += "Asddsa";
}
public void fourthMethod() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("raz");
stringBuilder.append(f);
stringBuilder.append("dwa");
f = stringBuilder.toString();
}
public void fifthMethod() {
e = e + "asd " + a + b+ c+ d+ e+ f;
}
public static void main(String[] args) {
ManyMethods manyMethods = new ManyMethods();
manyMethods.firstMethod();
manyMethods.secondMethod();
manyMethods.thridMethod();
manyMethods.fourthMethod();
manyMethods.fifthMethod();
}
}
Będzie to nasz wyjściowy kod, od którego będziemy robić wszystkie modyfikacje.
Wykonajmy następujące modyfikacje kodu:
- Zmieńmy nazwy metod i pól
public class ManyMethodsDifferentNames { private int firstIntegerVariable; private int secondIntegerVariable; private double firstDoubleVariable; private double secondDoubleVariable; private String firstStringVariable; private String secondStringVariable; public ManyMethodsDifferentNames() { firstIntegerVariable = 4; secondIntegerVariable = 1; firstDoubleVariable = -1.43; secondDoubleVariable = 9.12; firstStringVariable = "test"; secondStringVariable = "asdasd"; } public void doSomeActionOne() { firstIntegerVariable = firstIntegerVariable + secondIntegerVariable; } public void doSomeActionTwo() { firstIntegerVariable = firstIntegerVariable* firstIntegerVariable* firstIntegerVariable* firstIntegerVariable* firstIntegerVariable *firstIntegerVariable / 2*firstIntegerVariable; secondIntegerVariable = (int) (secondIntegerVariable + firstIntegerVariable -8 + 9 * firstDoubleVariable); } public void doSomeActionThird() { firstDoubleVariable *= 123.432; firstStringVariable += "Asddsa"; } public void doSomeActionFour() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("raz"); stringBuilder.append(secondStringVariable); stringBuilder.append("dwa"); secondStringVariable = stringBuilder.toString(); } public void doSomeActionFive() { firstStringVariable = firstStringVariable + "asd " + firstIntegerVariable + secondIntegerVariable+ firstDoubleVariable+ secondDoubleVariable+ firstStringVariable+ secondStringVariable; } public static void main(String[] args) { ManyMethodsDifferentNames manyMethods = new ManyMethodsDifferentNames(); manyMethods.doSomeActionOne(); manyMethods.doSomeActionTwo(); manyMethods.doSomeActionThird(); manyMethods.doSomeActionFour(); manyMethods.doSomeActionFive(); } } - Przenieśmy operacje z metod do metody main, a same metody usuńmy
public class ManyMethodsIncluded { private static int a; private static int b; private static double c; private static double d; private static String e; private static String f; public static void main(String[] args) { a = 4; b = 1; c = -1.43; d = 9.12; e = "test"; f = "asdasd"; a = a + b; a = a* a* a* a* a *a / 2*a; b = (int) (b + a -8 + 9 * c); c *= 123.432; e += "Asddsa"; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("raz"); stringBuilder.append(f); stringBuilder.append("dwa"); f = stringBuilder.toString(); e = e + "asd " + a + b+ c+ d+ e+ f; } } - Dodajmy kilka nieużywanych metod
public class ManyMethodsUnnecessaryStaff { private int a; private int b; private double c; private double d; private String e; private String f; public void stupidMethodOne() { f = "asd sa dsa" + " dsad sad sa" + f + "dsa dsa "; e += "dsadsa dsa dsa + dsad sa " + " dsad sadsa"; } public ManyMethodsUnnecessaryStaff() { a = 4; b = 1; c = -1.43; d = 9.12; e = "test"; f = "asdasd"; } public void stupidMethodTwo() { a = Math.abs(-123213213*3*5); b += 3* b + a + c; } public void firstMethod() { a = a + b; } public void stupidMethodThree() { c = 123.543534/42.543*423.123+65.2; d = Math.sqrt(c + d); } public void secondMethod() { a = a* a* a* a* a *a / 2*a; b = (int) (b + a -8 + 9 * c); } public void stupidMethodFour() { e = "olelele"; try { Thread.sleep(200); } catch(Exception e) { f = "hahah"; } } public void thridMethod() { c *= 123.432; e += "Asddsa"; } public void stupidMethodFive() { c = 123.543534/42.543*423.123+65.2; d = Math.sqrt(c + d); } public void fourthMethod() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("raz"); stringBuilder.append(f); stringBuilder.append("dwa"); f = stringBuilder.toString(); } public void stupidMethodSix() { e = "olelele"; try { Thread.sleep(200); } catch(Exception e) { f = "hahah"; } } public void fifthMethod() { e = e + "asd " + a + b+ c+ d+ e+ f; } public static void main(String[] args) { ManyMethodsUnnecessaryStaff manyMethods = new ManyMethodsUnnecessaryStaff(); manyMethods.firstMethod(); manyMethods.secondMethod(); manyMethods.thridMethod(); manyMethods.fourthMethod(); manyMethods.fifthMethod(); } } - Czwartym kodem do porównania, będzie kopia oryginalnego kodu
Testujemy!
Stwórzmy prostą metodę, która wczyta nasze kody źródłowe oraz wywoła naszą aplikacje i wyliczy prawdopodobieństwo.
fun main(args: Array<String>) {
val root = "C:\\kody_do_testow\\";
val oryg = FileInputStream(root + "oryg\\ManyMethods.java").bufferedReader().use { it -> it.readText() }
val code1 = FileInputStream(root + "diff_names\\ManyMethodsDifferentNames.java").bufferedReader().use { it -> it.readText() }
val code2 = FileInputStream(root + "included\\ManyMethodsIncluded.java").bufferedReader().use { it -> it.readText() }
val code3 = FileInputStream(root + "unn_staff\\ManyMethodsUnnecessaryStaff.java").bufferedReader().use { it -> it.readText() }
val code4 = FileInputStream(root + "oryg\\ManyMethods.java").bufferedReader().use { it -> it.readText() }
var calculate = PlagDetectorAlgorithm().calculate(LexerType.JAVA_8, oryg, code1)
println(String.format("code1 d=%.2f, px=%.2f, py=%.2f", calculate.d, calculate.px, calculate.py))
calculate = PlagDetectorAlgorithm().calculate(LexerType.JAVA_8, oryg, code2)
println(String.format("code2 d=%.2f, px=%.2f, py=%.2f", calculate.d, calculate.px, calculate.py))
calculate = PlagDetectorAlgorithm().calculate(LexerType.JAVA_8, oryg, code3)
println(String.format("code3 d=%.2f, px=%.2f, py=%.2f", calculate.d, calculate.px, calculate.py))
calculate = PlagDetectorAlgorithm().calculate(LexerType.JAVA_8, oryg, code4)
println(String.format("code4 d=%.2f, px=%.2f, py=%.2f", calculate.d, calculate.px, calculate.py))
}
Omówmy wyniki!
Pora na krótką analizę wyników.
- Zmienione nazwy metod i pól
Program zwrócił następujący wynik:d=0.97, px=0.98, py=0.98
Tutaj możemy zauważyć, że program poradził sobie całkiem nieźle. Wskaźniki są bardzo bliskie 1, więc możemy z dużą dozą prawdopodobieństwa stwierdzić, że porównywane programy zawierają ten sam kod.
- Kod z metod przeniesiony do głównej metody
Zwrócony wynik:d=0.57, px=0.69, py=0.76
Tutaj niestety algorytm poradził sobie dużo gorzej. Wystarczyła drobna zmiana w kodzie i stopień wykrywalności jest o wiele mniejszy. Może to byś spowodowane tym, że testowany kod jest krótki i nawet takie małe zmiany znacząco wpływają na wyniki. Warto na pewno się temu przyjrzeć w przyszłości.
- Kod z nieużywanymi metodami
Wyliczone podobieństwo:d=0.63, px=0.92, py=0.67
Na tym przykładzie możemy zobaczyć w praktyce wykorzystanie wskaźników px oraz py. O ile główny wskaźnik wynosi tylko 0.63 i nie musi wydawać się podejrzany, o tyle wartość wskaźnika px (0.92) mocno wskazuje, że jeden z porównywanych kodów zawiera dużą część drugiego kodu, oraz że mógł zajść plagiat.
- Porównanie dwóch identycznych kodów źródłowych
Wynik:d=0.97, px=0.98, py=0.98
Tutaj podobnie jak w pierwszym przypadku algorytm poradził sobie bardzo dobrze i wyliczył wskaźniki bliskie 1.
Podsumowanie
Dzisiaj wykonaliśmy pierwsze testy naszego algorytmu. Do testów użyliśmy kilka spreparowanych kodów źródłowych. Pierwsze wyniki wskazują, że algorytm jakieś prawdopodobieństwo wylicza 😉
W następnym wpisie odnośnie PlagDetectora przeprowadzimy testy na kodach źródłowych z28za czasów studenckich 😉


Dodaj komentarz