// Copyright (c) CNES 2008 // // This software is part of CelestLab, a CNES toolbox for Scilab // // This software is governed by the CeCILL license under French law and // abiding by the rules of distribution of free software. You can use, // modify and/ or redistribute the software under the terms of the CeCILL // license as circulated by CEA, CNRS and INRIA at the following URL // 'http://www.cecill.info'. //----------------------------------------------------------- // Executes tests (CL__execTests()) and does coverage analysis. // Generates 2 specific output files (in CL_home()): // - cov_report_syn.txt => synthesis // - cov_report_det.txt => detailed results //----------------------------------------------------------- function [] = CL__execTestsCov() function [covres] = process_profile(listfuncs) //----------------------------------------------------------- // Executes profile for each function et generates results // listfuncs: list of function structures (dim = N) // covres: structure with fields: // nblig_exec: number of executable lines (1xN) // nblig_cov: number of executed lines (1xN) // numlig_not_cov: (string) not executed lines numbers (1xN) // cov_ratio: coverage ratio = nblig_cov/nblig_exec (1xN) //----------------------------------------------------------- N = size(listfuncs); covres = struct(); covres.nblig_exec = zeros(1,N); // executables covres.nblig_cov = zeros(1,N); // executed covres.numlig_not_cov = emptystr(1,N); covres.cov_ratio = zeros(1,N); covres.ok = zeros(1,N); for k = 1 : size(listfuncs) func = listfuncs(k) fn = evstr(func.name); prof_result = profile(fn); ok = 1; // 1 if no inconsistency if (size(prof_result, 1) <> size(func.txt,1)) CL__warning("Inconsistent profile results, func = " + func.name); ok = 0; end // prof: same size as func.txt = number of executions prof = zeros(func.txt); nres = min(size(prof_result,1), size(func.txt,1)); prof(1:nres) = prof_result(1:nres,1); // executable lines (1 if yes) lig_exec = zeros(func.txt); lig_exec(func.ind_exec) = 1; // Generates output. nblig_exec = length(find(lig_exec == 1)); nblig_cov = length(find(lig_exec == 1 & prof > 0)); numlig_not_cov = []; I = find(lig_exec == 1 & prof == 0); if (I <> []); numlig_not_cov = func.ndeb + I - 1; end ratio = nblig_cov / nblig_exec; covres.nblig_exec(k) = nblig_exec; covres.nblig_cov(k) = nblig_cov; covres.numlig_not_cov(k) = ""; covres.numlig_not_cov(k) = strcat(string(numlig_not_cov), " "); covres.cov_ratio(k) = ratio; covres.ok(k) = ok; end endfunction //----------------------------------------------------------- // indices of sorted results // all functions in same file are gathered // sorting criterion: average ratio of functions in same file // listfuncs: list of function structures (dim = N) // covres: coverage results (structure containing 1xN fields) //----------------------------------------------------------- function [I_sort] = sort_res(listfuncs, covres) // make (row) vectors fnames = emptystr(1,size(listfuncs)); names = emptystr(1,size(listfuncs)); for k = 1 : size(listfuncs) fnames(k) = listfuncs(k).fname; names(k) = listfuncs(k).name; end // computes average coverage ratio for each fname fnames_u = unique(fnames); ratios = zeros(fnames_u); for k = 1 : size(fnames_u,2) I = find(fnames == fnames_u(k)); ratios(k) = sum(covres.nblig_cov(I),"c") / .. sum(covres.nblig_exec(I),"c") ; end [ratios,I] = gsort(ratios,"c","d"); I_sort = []; for (i = I) K = find(fnames == fnames_u(i)); k1 = find(fnames(K) == names(K)); k2 = find(fnames(K) <> names(K)); I_sort = [I_sort, K(k1), K(k2)]; end endfunction //----------------------------------------------------------- // Generates report (detailed results). // listfuncs: list of function structures (dim = N) // covres: coverage results (structure containing 1xN fields) // fpath: path of output file //----------------------------------------------------------- function gen_report1(listfuncs, covres, fpath) [fd,err] = mopen(fpath,"w"); if (err <> 0) CL__error("Error opening file " + fpath); end mfprintf(fd,"# --------------------------------------------------\n"); mfprintf(fd,"# %s - Coverage analysis\n", CL_version()); mfprintf(fd,"# (Detailed results)\n"); mfprintf(fd,"# \n"); mfprintf(fd,"# Number of functions: %d\n", size(listfuncs)); mfprintf(fd,"# --------------------------------------------------\n"); // sort: ratio in decreasing order (all functions) [ratio, I_sort] = gsort(covres.cov_ratio, "c", "d"); for i = 1 : size(listfuncs) k = I_sort(i); func = listfuncs(k); name = func.name; fname = func.fname; if (name <> fname) name = sprintf("%s (%s)", name, fname); end nblig_exec = covres.nblig_exec(k); nblig_cov = covres.nblig_cov(k); numlig_not_cov = covres.numlig_not_cov(k); ratio = covres.cov_ratio(k); ok = covres.ok(k); mfprintf(fd,"Function: %s\n", name); mfprintf(fd,"File: %s\n", func.fpath); mfprintf(fd,"Not executed lines (in file): %s\n", numlig_not_cov); mfprintf(fd,"Number of executed lines: %d\n", nblig_cov); mfprintf(fd,"Number of executable lines: %d\n", nblig_exec); mfprintf(fd,"Coverage ratio (%%): %d\n", round(ratio * 100)); if (~ok); mfprintf(fd,"Validity: ???\n"); end mfprintf(fd,"\n"); end mclose(fd); endfunction //----------------------------------------------------------- // Generates report (synthesis). // listfuncs: list of function structures (dim = N) // covres: coverage results (structure containing 1xN fields) // fpath: path of output file //----------------------------------------------------------- function [] = gen_report2(listfuncs, covres, fpath) [fd,err] = mopen(fpath, "w"); if (err <> 0) CL__error("Error opening file " + fpath); end mfprintf(fd,"# --------------------------------------------------\n"); mfprintf(fd,"# %s - Coverage analysis\n", CL_version()); mfprintf(fd,"# (Synthetic results)\n"); mfprintf(fd,"# \n"); mfprintf(fd,"# Number of functions: %d\n", size(listfuncs)); mfprintf(fd,"# \n"); mfprintf(fd,"# Total number of executed lines: %d\n", sum(covres.nblig_cov)); mfprintf(fd,"# Total number of executable lines: %d\n", sum(covres.nblig_exec)); mfprintf(fd,"# Total coverage ratio (%%): %d\n", .. round(100 * sum(covres.nblig_cov)/sum(covres.nblig_exec))); mfprintf(fd,"# Average coverage ratio (%%): %d\n", .. round(100 * mean(covres.cov_ratio))); mfprintf(fd,"# \n"); mfprintf(fd,"# Column 1: Main function name\n"); mfprintf(fd,"# Column 2: Coverage ratio (%%)\n"); mfprintf(fd,"# Column 3: Number of executed lines\n"); mfprintf(fd,"# Column 4: Number of executable lines\n"); mfprintf(fd,"# Column 5: Function name (when useful)\n"); mfprintf(fd,"# --------------------------------------------------\n"); // sort: ratio in decreasing order I_sort = sort_res(listfuncs, covres); for i = 1 : size(listfuncs) k = I_sort(i); func = listfuncs(k); name = func.name; fname = func.fname; if (fname == name); name = ""; else; fname = ""; end nblig_exec = covres.nblig_exec(k); nblig_cov = covres.nblig_cov(k); ratio = covres.cov_ratio(k); mfprintf(fd,"%-28s %6d %6d %6d %s\n", fname, round(100 * ratio), nblig_cov, nblig_exec, name); end mclose(fd); endfunction // ========================================================== // MAIN // ========================================================== mprintf("-----------------------------------------\n"); mprintf(" CelestLab - Tests and Coverage \n"); mprintf("-----------------------------------------\n"); // directory for result files dir_result = CL_home(); // root directory for sci files dir_macros = fullfile(CL_home(), "macros"); // file to be excluded (part of pathname) excl = fullfile(dir_macros, "Misc"); // Names of coverage reports fname_res1 = fullfile(dir_result, "cov_report_det.txt"); fname_res2 = fullfile(dir_result, "cov_report_syn.txt"); // --- extract functions mprintf("Loading functions from %s\n", dir_macros); fpaths = CL_path("*.sci", dir_macros, "all"); // remove excluded files for name = excl I = grep(fpaths, name); fpaths(I) = []; end [listfuncs, ok] = CL__extractFunctions(fpaths); if (~ok) mprintf("\n=> Coverage analysis cancelled!\n"); return; end // --- exec and prepare for profiling // no warning if function already defined ! prot = funcprot(); funcprot(0); // exec sci files mprintf("Exec-ing functions and adding profile info\n"); // temp file for exec (as execstr does not work if ".." exists) ftmp = fullfile(TMPDIR, "CL__" + sprintf("%d\n", getdate("s")) + ".txt"); for k = 1 : size(listfuncs) func = listfuncs(k); mputl(func.txt, ftmp); err = exec(ftmp, "errcatch", -1); if (err <> 0) CL__error("Error loading function number %d\n", k); end remove_profiling(func.name); add_profiling(func.name); end // remove temp file mdelete(ftmp); // --- execute tests (fonction standard) mprintf("Tests execution\n"); CL__execTests(); mprintf("\n"); // --- profile and process mprintf("Profiling and processing results\n"); covres = process_profile(listfuncs); // NB profiling info not removed // mprintf("Removing profile info\n"); // for k = 1 : size(listfuncs) // func = listfuncs(k); // remove_profiling(func.name); // end // restore mode funcprot(prot); // --- generate reports mprintf("Generating reports in %s\n", dir_result); gen_report1(listfuncs, covres, fname_res1); gen_report2(listfuncs, covres, fname_res2); mprintf("End of coverage analysis\n"); endfunction