-
Notifications
You must be signed in to change notification settings - Fork 0
/
LanceurProjet.java
761 lines (655 loc) · 18.9 KB
/
LanceurProjet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
import java.awt.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
/**
* cree une classe d'Exception qui remonte sans verifier le try catch
*
* @author vthomas
*
*/
class LanceurTestException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* constructeur avec un message
*
* @param s
* message d'erreur
*/
public LanceurTestException(String s) {
super(s);
}
}
/**
* permet d'afficher la barre horizontale
*
* @author vthomas
*
*/
class LanceurBarre extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
// pour l'affichage des statistiques
int nbOk;
int nbErreur;
int nbEchec;
int nbTests;
// pour gerer la taille de la barre
int tailleX = 400;
int TailleY = 80;
public static final int decalX = 20; // a partir de quand decaler
// la barre
public static final int decalY = 10; // a partir de quand decaler
// la barre
public static final int BarreY = 40; // taille de la barre en Y
/**
* met a jour la barre de status
*
* @param PnbOk
* nombre de ok
* @param PnbErreur
* nombre erreurs
* @param PnbEchec
* nombre echec
*/
public void miseAJour(int PnbOk, int PnbErreur, int PnbEchec) {
nbOk = PnbOk;
nbEchec = PnbEchec;
nbErreur = PnbErreur;
nbTests = nbOk + nbEchec + nbErreur;
repaint();
}
public LanceurBarre() {
super();
setPreferredSize(new Dimension(tailleX, TailleY));
}
public void paint(Graphics g) {
super.paint(g);
// s'il n'y a pas de tests, on ne fait rien
if (nbTests == 0)
return;
// met a jour l'affichage de la barre
int tailleXBarre = tailleX - 2 * decalX;
int decalage = decalX;
// le OK
int finOK = (tailleXBarre * nbOk) / nbTests;
g.setColor(Color.green);
g.fillRect(decalage, decalY, finOK, BarreY);
decalage += finOK;
// le echec
g.setColor(Color.orange);
int finEchec = (tailleXBarre * nbEchec) / nbTests;
g.fillRect(decalage, decalY, finEchec, BarreY);
decalage += finEchec;
// le erreur
g.setColor(Color.red);
int finErreur = (tailleXBarre * nbErreur) / nbTests;
g.fillRect(decalage, decalY, finErreur, BarreY);
decalage += finErreur;
// dessin rectangle
g.setColor(Color.black);
g.drawRect((tailleX - tailleXBarre) / 2, decalY,
tailleXBarre, BarreY);
g.drawString("Tests: " + nbTests, 0, TailleY - 10);
g.drawString("Ok: " + nbOk, 100, TailleY - 10);
g.drawString("Echec: " + nbEchec, 200, TailleY - 10);
g.drawString("Erreur: " + nbErreur, 300, TailleY - 10);
g.dispose();
}
}
/**
* permet de logguer les resultats de test
*
* @author vthomas
*
*/
class LanceurLog {
// le nom de la methode de test
public String nomMethode;
// le type soit une erreur, soit un echec
public String type;
// class ou se trouve l'erreur
public String classOuErreur;
// ligne ou se trouve l'erreur
public String LigneErreur;
// exception declencheuse
public Throwable exception;
/**
* interface graphique
*/
// JPanel de labarre
static LanceurBarre barre;
// JTree des tests
static JTree tree;
public LanceurLog() {
type = "Ok";
}
/**
* affiche un log d'erreur
*/
public String toString() {
String resultat = ("***** Test " + nomMethode + " **********************************\n");
// si il y eu une erreur
if (exception != null) {
resultat += (" - Type: " + type + "\n");
resultat += (" - Classe: " + classOuErreur);
resultat += (", Ligne: " + LigneErreur + "\n");
resultat += (" - Message: " + exception.getMessage() + "\n");
// affiche exception
StackTraceElement[] traces = exception.getStackTrace();
for (StackTraceElement trace : traces) {
// on arrete de faire la pile des qu'on arrive a
// l'invocation de lanceur
if (trace.getClassName().equals(
"sun.reflect.NativeMethodAccessorImpl"))
break;
// sinon on remonte la pile d'appel
resultat += " -> " + trace.getClassName()
+ " at " + trace.getFileName() + "("
+ trace.getLineNumber() + ")\n";
}
} else {
resultat += " - OK\n";
}
resultat += ("***** fin " + nomMethode + " **********************************\n\n");
// exception.printStackTrace();
return (resultat);
}
/**
* permet de mettre a jour l'affichage a partir le la liste des
* logs
*
* @param logs
* liste des logs a afficher
*/
public static void afficheGraphiqueListeLogs(
ArrayList<LanceurLog> logs) {
// met l'arbre a jour
miseAJourTree(logs);
// met la barre ajour
miseAJourBarre(logs);
}
/**
* fait les calculs pour la mise a jour de la barre
*
* @param logs
* une liste de log
*/
public static void miseAJourBarre(ArrayList<LanceurLog> logs) {
// calculs log
int nbTests = logs.size();
int nbErreur = 0;
int nbEchec = 0;
int nbOk = 0;
for (LanceurLog l : logs) {
if (l.type.equals("Ok"))
nbOk++;
if (l.type.equals("Erreur"))
nbErreur++;
if (l.type.equals("Echec"))
nbEchec++;
}
barre.miseAJour(nbOk, nbErreur, nbEchec);
}
/**
* met a jour l'arbre
*
* @param logs
* la liste des Logs
*/
public static void miseAJourTree(ArrayList<LanceurLog> logs) {
// mettre a jour tree
tree.removeAll();
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
DefaultMutableTreeNode root = new DefaultMutableTreeNode(
"<html><font color=black>Resultats de <b>"
+ LanceurProjet.classDeTest.getClass().getName()
+ "</b></text></font></html>");
model.setRoot(root);
// ajouter resultats des tests
for (LanceurLog l : logs) {
String r = "l.nomMethode";
String color = "black";
// determine la couleur des branches
color = choixCouleurTree(l, color);
r = "<html><font color=" + color + ">" + l.nomMethode
+ " - " + l.type + "</font></html>";
DefaultMutableTreeNode log = new DefaultMutableTreeNode(r);
// contenu du log en cas d'erreur
if (l.type.equals("Erreur") || l.type.equals("Echec")) {
r = "Classe: " + l.classOuErreur + ", Ligne: "
+ l.LigneErreur;
DefaultMutableTreeNode endroit = new DefaultMutableTreeNode(
r);
log.add(endroit);
r = "Message: " + l.exception.getMessage();
DefaultMutableTreeNode message = new DefaultMutableTreeNode(
r);
log.add(message);
// parcours exception en cas d'erreur
if (l.type.equals("Erreur")) {
// on affiche le contenu de l'exception qui est
// remontee
r = "<html><b>"
+ l.exception.getClass().getName()
+ "</b></html>";
DefaultMutableTreeNode except = new DefaultMutableTreeNode(
r);
log.add(except);
// on parcourt la pile d'appel
for (StackTraceElement stack : l.exception
.getStackTrace()) {
// si on arrive dans les classes d'invocation
if (stack
.getClassName()
.equals("sun.reflect.NativeMethodAccessorImpl"))
break;
r = "" + stack;
DefaultMutableTreeNode stackelement = new DefaultMutableTreeNode(
r);
except.add(stackelement);
}
}
}
// ajout du log a l'arbre
root.add(log);
}
tree.expandRow(0);
}
/**
* associe les couleurs au log
*
* @param l
* le log concerne
* @param color
* la couleur associee
* @return la chaine represetant la couleur
*/
public static String choixCouleurTree(LanceurLog l, String color) {
if (l.type.equals("Ok"))
color = "green";
if (l.type.equals("Erreur"))
color = "red";
if (l.type.equals("Echec"))
color = "orange";
return color;
}
/**
* affiche la JFrame et creer les attrbuts de l'interface
*/
public static void creeInterface() {
// creation JFRame
JFrame frame = new JFrame();
// met un bouton pour relancer les tests
JButton lanceTests = new JButton("relancer tests");
// le listenre pour lancer les tests
lanceTests.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
LanceurProjet.lanceSansInterface(LanceurProjet.classDeTest);
}
});
// Le JPanel qui affiche la barre verte ou rouge
barre = new LanceurBarre();
// Le JTree
DefaultMutableTreeNode top = new DefaultMutableTreeNode(
"Resultats de la classe "
+ LanceurProjet.classDeTest.getClass());
DefaultMutableTreeNode t1 = new DefaultMutableTreeNode(
"test1 + ok");
t1.add(new DefaultMutableTreeNode("descriptif"));
t1.add(new DefaultMutableTreeNode("Exceptions"));
top.add(t1);
DefaultMutableTreeNode t2 = new DefaultMutableTreeNode(
"test2 + ok");
t2.add(new DefaultMutableTreeNode("descriptif"));
t2.add(new DefaultMutableTreeNode("Exceptions"));
top.add(t2);
tree = new JTree(top);
JScrollPane scroll = new JScrollPane(tree);
scroll.setPreferredSize(new Dimension(400, 400));
// le JPanel global
JPanel global = new JPanel();
global.setLayout(new BorderLayout());
global.add(barre, BorderLayout.NORTH);
global.add(scroll, BorderLayout.CENTER);
global.add(lanceTests, BorderLayout.SOUTH);
frame.setContentPane(global);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* affiche tous les logs
*
* @param logs
*/
public static void afficheTexteListeLogs(
ArrayList<LanceurLog> logs) {
// affichage de la classe de test
System.out.println(LanceurProjet.classDeTest.getClass());
System.out.println("Test numéro" + LanceurProjet.numLancer);
// calculs log
int nbTests = logs.size();
int nbErreur = 0;
int nbEchec = 0;
int nbOk = 0;
for (LanceurLog l : logs) {
if (l.type.equals("Ok"))
nbOk++;
if (l.type.equals("Erreur"))
nbErreur++;
if (l.type.equals("Echec"))
nbEchec++;
}
// affiche le resulta global
System.out.println("nb test:" + nbTests);
System.out.println("nb Ok:" + nbOk);
System.out.println("nb echec:" + nbEchec);
System.out.println("nb erreur:" + nbErreur);
System.out.println("\n");
// afiche logs
for (LanceurLog l : logs) {
System.out.println(l);
}
System.out.println("\n");
System.out
.println("************************************************************\n");
}
}
/**
* lanceur de test unitaire
*
* @author vthomas
*
*/
public class LanceurProjet {
/**
* le nombre de lancement
*
*/
static int numLancer = 0;
/**
* la classe qu icontient les tests
*/
static Object classDeTest;
/**
* methode statique de test qui echoue
*/
public static void fail(String erreur) {
throw new LanceurTestException(erreur);
}
/**
* methode statique de comparaison
*/
public static void assertEquals(Object attendu, Object obtenu,
String erreur) {
// si on test des references null
if (attendu == null) {
if (obtenu != null)
throw new LanceurTestException(erreur + " [attendu=>"
+ attendu + ", obtenu=>" + obtenu + "]");
}
// sinon on peut tester egalite
else if (!attendu.equals(obtenu))
throw new LanceurTestException(erreur + " [attendu=>"
+ attendu + ", obtenu=>" + obtenu + "]");
}
/**
* lance les test mais avec une option graphique
*
* @param classDeTest
* la classe de Test
*/
public static void lanceAvecInterface(Object classTest) {
// sauve la classe de test
classDeTest = classTest;
// lance interface grpahique
LanceurLog.creeInterface();
// lance le premier test
lanceSansInterface(classTest);
}
/**
* lance les tests
*
* @param test
* l'objet correspondant a la classe de test
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ClassNotFoundException
*
*/
public static void lanceSansInterface(Object test) {
classDeTest = test;
// recharge a chaud les classes avec un nouveau classLoader
rechargeAChaud();
// inxcrementer le nombre de lancer
numLancer++;
// recupere les methodes de test
Method[] methodes = test.getClass().getMethods();
// les garde si elles contiennent test
ArrayList<Method> listeMethodes;
listeMethodes = filtreMethodes(methodes);
// on trie les methodes
trieLesMethodesParNom(listeMethodes);
// System.out.println(listeMethodes);
// liste de l'ensemble des logs
ArrayList<LanceurLog> listeLogs = new ArrayList<LanceurLog>();
// lance tous les tests
for (Method methodeATester : listeMethodes) {
LanceurLog log = testeUneMethode(test, methodeATester);
listeLogs.add(log);
}
// affiche l'ensemble des log
// Log.afficheTexteListeLogs(listeLogs);
LanceurLog.afficheGraphiqueListeLogs(listeLogs);
}
/**
* permet de recharger les classes a chaud
*/
public static void rechargeAChaud() {
URL u, u2 = null;
try {
u = new File("").toURI().toURL();
u2 = new File("bin").toURI().toURL();
URL[] url = { u, u2 };
URLClassLoader ucl = new URLClassLoader(url, null);
Class classAn = ucl.loadClass(classDeTest.getClass()
.getName());
LanceurProjet.classDeTest = classAn.newInstance();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* permet de tester une methode
*
* deux cas se produisent - soit elle renvoie une
* InvocationException et il
* y a une erreur dans l'appel - si c'est un cause par un
* TestException ==
* failure - sinon c'est une exception interne - soit elle ne
* renvoie rien
* et c'est ok
*
*
* @param test
* @param methodeATester
*/
public static LanceurLog testeUneMethode(Object test,
Method methodeATester) {
// construction du log
LanceurLog l = new LanceurLog();
l.nomMethode = methodeATester.getName();
try {
methodeATester.invoke(test, new Object[0]);
} catch (InvocationTargetException e) {
// vient a cause d'un test echoue
// voir l'exception interne
Throwable exceptionInterne = e.getCause();
// afin d'eviter les problemes dans le nouveau
// rechargement de classes
// (les classes ne sont pas les memes et instance of ne
// fonctionne donc pas)
if (exceptionInterne.getClass().getSimpleName()
.equals("LanceurTestException")) {
// c'est une exception due a un test echoue
creeLogTestEchec(exceptionInterne, l);
} else {
creeLogTestErreur(exceptionInterne, l);
}
} catch (IllegalAccessException e) {
System.out
.println("erreur importante de l'appli de test!!!");
e.printStackTrace();
} catch (IllegalArgumentException e) {
System.out
.println("erreur importante de l'appli de test!!!");
e.printStackTrace();
}
return (l);
}
/**
* Log en cas d'erreur
*
* @param exceptionInterne
* exception qui genere l'erreur
* @param log
* le log ou sauver
*/
public static void creeLogTestErreur(Throwable exceptionInterne,
LanceurLog log) {
// mise a jour du log
log.type = "Erreur";
// indice dans le stacktrace
int indiceLigne = 1;
// faut voir si la methode appelee est verifier ou pas.
if (exceptionInterne.getStackTrace()[1].getMethodName()
.equals("verifier")) {
// c'est qu'il faut descendre d'un cran dans la stacktrace
indiceLigne = 2;
}
log.classOuErreur = exceptionInterne.getStackTrace()[indiceLigne]
.getFileName();
log.LigneErreur = ""
+ exceptionInterne.getStackTrace()[indiceLigne]
.getLineNumber();
log.exception = exceptionInterne;
}
/**
* methode qui affiche que le test echoue
*
* @param exceptionInterne
* l'erreur qui explique ou le test echoue
*/
public static void creeLogTestEchec(Throwable exceptionInterne,
LanceurLog log) {
// mise a jour du log
log.type = "Echec";
// indice dans le stacktrace
int indiceLigne = 1;
// faut voir si la methode appelee est verifier ou pas.
if (exceptionInterne.getStackTrace()[1].getMethodName()
.equals("verifier")) {
// c'est qu'il faut descendre d'un cran dans la stacktrace
indiceLigne = 2;
}
log.classOuErreur = exceptionInterne.getStackTrace()[indiceLigne]
.getFileName();
log.LigneErreur = ""
+ exceptionInterne.getStackTrace()[indiceLigne]
.getLineNumber();
log.exception = exceptionInterne;
}
/**
* filtre les methodes et ne garde que les methodes commencant par
* test
*
* @param methodes
* liste des methodes
* @return liste des methodes avec test dans leur nom
*/
public static ArrayList<Method> filtreMethodes(Method[] methodes) {
ArrayList<Method> listeMethodes;
listeMethodes = new ArrayList<Method>();
for (Method m : methodes) {
// si son nom commence par test, on l'ajoute
if (m.getName().substring(0, 4).equals("test"))
listeMethodes.add(m);
}
return listeMethodes;
}
/**
* trie les methodes selon leur numero
*
* @param listeMethodes
*/
public static void trieLesMethodesParNom(
ArrayList<Method> listeMethodes) {
// on trie les methodes par numero
Comparator<Method> compMethode = new Comparator<Method>() {
@Override
public int compare(Method methode0, Method methode1) {
int n0 = getNumeroMethode(methode0);
int n1 = getNumeroMethode(methode1);
if (n0 < n1) {
return (-1);
}
if (n0 > n1) {
return (1);
}
return 0;
}
/**
* claulce le numero de la methode
*
* @param methode0
* methode dont on cherche le numero
* @return numero de methode
*/
public int getNumeroMethode(Method methode0) {
try {
String[] tab = methode0.getName().split("_");
if (tab.length > 1)
return Integer.parseInt(tab[1]);
} catch (NumberFormatException e) {
}
return (-1);
}
};
Collections.sort(listeMethodes, compMethode);
}
}