5.3 Xây dựng công cụ kiểm tra độ phủ
5.3.1 Phân tích dữ liệu log
Phân tích biên tập giá trị vết thu được, từ file vết(file log) đã thu được chương trình sẽ biên tập lại thành các lớp con có chức năng chứa các thông tin về quá trình chạy chương trình như các lớp lưu trữ tên lớp, tên phương thức,… Các class đã thêm vào để xử lý việc đọc log gồm:
- FileReader.java: đọc file log lên và lưu thành một danh sách các dòng vết - LogParser.java: đầu vào là một danh sách các dòng từ đầu ra của
FileReader
Lặp qua danh sách này và chuyển thông tin vết vào các class sau:
o LineEntry.java: chứa thông tin của một dòng vết.
o ClassEntry: chứa thông tin của một class.
o MethodEntry: chứa thông tin của một method.
o BranchKeyWorld.java: chứa những key word bắt đầu một nhánh như: if, else, while,….
ConsolePublisher LogAnalysic LogParser FileReader SourceParser
doAnalysic() parseLog() readFile() write resultToHtml() list lines parsesSource() list SourceClassEntry HtmlGenerator list ClassEntry
39
Hình 5.4: Biểu đồ tuần tự quá trình phân tích dữ liệu vết(log)
Quá trình phân tích file vết như sau: + Mở file vết.
+ Đọc lên từng dòng trong file vết, nếu dòng này không phải là dòng cuối và đã bắt đầu vào nội dung vết của chương trình thì thêm nó vào một danh sách.
+ Nếu dòng đang xét là kết thúc thông tin vết của các lớp thì thoát khỏi vòng lặp.
public class FileReader {
private final static String START_POINT = "---
---Starting to print source code";
private final static String END_POINT = "---
---Ended to print source code";
public static List<String> readFile(String fileName, boolean
isSourceFile) throws IOException {
BufferedReader reader = new BufferedReader(new
java.io.FileReader(fileName));
List<String> listOfLines = new ArrayList<String>();
String line;
boolean startPoint = false;
while ((line = reader.readLine()) != null) {
if (!startPoint && line.contains(START_POINT)) {
startPoint = true;
continue; }
if (line.contains(END_POINT)) {
LogParser FileReader ClassEntry MethodEntry BranchEntry
readFile()
add class name list ClassEntry
add method name and codes
loop add list instances loop to creat instance log file list ClassEntry add list instances add branch
40 break; } if (isSourceFile || startPoint){ listOfLines.add(line); } } reader.close(); return listOfLines; } }
Xây dựng các lớp Entry để lưu trữ thông tin về dòng vết, lớp, hàm và nhánh.
Hình 5.5: Biểu đồ lớp phân tích dữ liệu vết
Một lớp sẽ có nhiều hàm, một hàm sẽ có nhiều nhánh, một nhánh có thể không chứa hoặc chứa nhiều nhánh con. Lớp LineEntry dùng để lưu trữ thông tin của dòng log bao gồm: tên lớp, chỉ số dòng trong code java, nội dung dòng code và chỉ số dòng đó trong file log. Lặp qua từng dòng log trong danh sách các dòng log, đưa thông tin từng dòng log vào từng đối tượng LineEntry.
public static List<ClassEntry> parseLog(String fileName) throws
IOException {
List<String> listOfLines = FileReader.readFile(fileName, false);
List<LineEntry> lineEntryList = new ArrayList<LineEntry>();
int index = 0;
for (String line : listOfLines) {
String[] arrays = line.split(".java");
String className = arrays[0].trim();
int lineNumber =
41
String lineInfo = arrays[1].split(":")[2];
if (!lineInfo.contains(MY_EXCEPTION)){
lineEntryList.add(new LineEntry(className, lineNumber,
lineInfo, index)); }
index++; }
List<ClassEntry> classEntries = getClassEntries(lineEntryList);
setMethodEntries(lineEntryList, classEntries); setBranchEntries(lineEntryList, classEntries); collectBranchesHaveSameMethod(lineEntryList, classEntries); reOrderBranches(lineEntryList, classEntries); return classEntries; }
- Lặp qua danh sách LineEntry, tìm thông tin các class và lưu vào danh sách ClassEntry. Đối với thông tin lớp có 2 trường hợp:
Lớp gọi hàm static : sẽ có dạng “<Tên lớp>.”
Lớp được khởi tạo trước khi gọi hàm : sẽ chứa tên lớp và dấu “(”. Tên lớp đã lưu trữ trong đối tượng LineEntry.
- Lặp qua từng ClassEntry trong danh sách ClassEntry, với mỗi đối tượng ClassEntry, lặp lại danh sách LineEntry để tìm thông tin của hàm. Sau đó lưu danh sách MethodEntry vào lại ClassEntry đang xét.
- Tương tự, lặp qua từng MethodEntry của ClassEntry, dựa vào danh sách LineEntry để tìm thông tin của nhánh và lưu vào danh sách BranchEntry của MethodEntry đang xét. Nếu dòng code nào bắt đầu bằng một trong các key word sau thì đó là nhánh: “if”, ”else”,“elseif”, “while”, “do”, ”for”, ”switch”, “case”.