Something went wrong on our end
-
Federico Felici authoredFederico Felici authored
check_headers.m 7.45 KiB
classdef check_headers < matlab.unittest.TestCase
% Checks whether desired copyright headers are in place
% Can be used to fix them automatically by setting `dofix=true`
% mytest = check_headers
% mytest.dofix = true; % changes property
% mytest.run; % runs
% Concrete sub-classes must redefine the abstract properties below
% They can also extend the check_and_fix_files method to add the
% TestTags attribute if needed.
%
% [ SCDDS - Simulink Control Development & Deployment Suite ] Copyright SPC-EPFL Lausanne 2022.
% Distributed under the terms of the GNU Lesser General Public License, LGPL-3.0-only.
properties (Abstract)
dofix logical % if true, modify files to fix header
IgnoredPaths cell % cell array of paths to ignore
old_headers cell % cell array of old headers to remove
desired_header cell % array of char with new desired header
end
methods (TestClassSetup)
function check_MATLAB_version(testCase)
testCase.assumeTrue(~verLessThan('matlab','9.2'),'check_headers tests are disabled for version 2016b and prior');
end
end
methods(Test)
function check_and_fix_files(testCase)
%% .m, .c and .h files
mfiles = dir(fullfile(testCase.test_folder,'**/*.m'));
cfiles = dir(fullfile(testCase.test_folder,'**/*.c'));
hfiles = dir(fullfile(testCase.test_folder,'**/*.h'));
files = [mfiles;cfiles;hfiles];
% remove ignored paths
files = files(~contains({files.folder},testCase.IgnoredPaths) & ...
~contains({files.name},testCase.IgnoredPaths));
if testCase.dofix && numel(files)>0
s = input(sprintf('this will check and fix %d files in %s/, are you sure? (y/n)',...
numel(files),testCase.test_folder),'s');
if ~contains(lower(s),'y'), return; end
end
failing_files = {}; % init
for ifile = 1:numel(files)
myfile = files(ifile);
filepath = fullfile(myfile.folder,myfile.name);
fprintf('checking file: %s.. ',filepath)
filewhole = fileread(filepath); % full listing
% check if old header text exists and remove it
if any(contains(filewhole,testCase.old_headers))
remove_unwanted_headers(filepath,testCase.old_headers,testCase.dofix);
end
% check if desired header exists
filewhole = fileread(filepath); % full listing
if all(cellfun(@(x) contains(filewhole,x),testCase.desired_header))
fprintf(' ok \n');
continue; % next file
else
fprintf(' NOT OK \n')
end
if testCase.dofix
% Add new help header
add_header(filepath,testCase.desired_header)
end
failing_files = [failing_files;{filepath}]; %#ok<AGROW>
end % loop on files
if ~testCase.dofix && ~isempty(failing_files)
errormsg = sprintf('These files did not contain the desired header: %s\n',failing_files{:});
testCase.assertFail(errormsg);
end
end
end
end
function remove_unwanted_headers(filename,old_headers,dofix)
% remove unwanted headers if any
for iunwanted = 1:numel(old_headers)
my_unwanted_header = old_headers{iunwanted};
grepcmd = sprintf('grep -n "%s" %s | cut -f1 -d:',my_unwanted_header,filename);
[s,w] = system(grepcmd);
assert(s==0,'error using grep: %s\n',w);
if ~isempty(w)
linenum = str2num(w); %#ok<ST2NM>
fprintf('found unwanted header on line %d\n',linenum)
if dofix
% replace special characters with escape char
my_unwanted_header_regexp = my_unwanted_header;
my_unwanted_header_regexp = strrep(my_unwanted_header_regexp,'+','\+');
my_unwanted_header_regexp = strrep(my_unwanted_header_regexp,'[','\[');
my_unwanted_header_regexp = strrep(my_unwanted_header_regexp,']','\]');
% remove unwanted header using sed
fprintf(' removing unwanted header\n')
sedcmd = sprintf('sed -i '''' ''/%s/d'' %s',my_unwanted_header_regexp,filename);
[s,w] = system(sedcmd);
assert(s==0,'error running sed: %s\n',w);
end
end
end
end
function add_header(filename,desired_header)
[~,~,ext] = fileparts(filename);
if strcmp(ext,'.m')
add_matlab_help_header(filename,desired_header);
else
add_top_header(filename,desired_header)
end
end
function add_top_header(filename,desired_header)
% add header at beginning of file
fprintf('adding header at the top of the file')
for ii=1:numel(desired_header)
my_desired_header = ['/* ',desired_header{ii},' */']; % add comment syntax
sedcmd = sprintf('sed -i '''' "1i \\\\\n%s\n" %s',my_desired_header,filename);
[s,w] = system(sedcmd);
assert(s==0,'error using sed.\nCommand: \n%s\nError:\n%s',sedcmd,w);
end
fprintf('\n');
end
function add_matlab_help_header(filepath,desired_header)
%% add desired header at the end of the help section
% find last help line
helptext = help(filepath);
[~,fname] = fileparts(filepath);
if contains(helptext,{...
sprintf('%s is a class',fname),...
sprintf('%s is a function',fname),...
sprintf('%s is a script',fname)})
% default help text means the file has no help
warning('%s has no help section, could not add header',filepath);
return
end
% find end of help section by looking for consecutive lines that start with %
grepcmd = sprintf('grep -n ''^\\s*%%'' %s | cut -f1 -d:',filepath);
[s,w] = system(grepcmd); assert(s==0,'error using grep:\n%s',w);
commentlines = str2num(w); %#ok<ST2NM> % lines with comments
if isempty(commentlines), warning('no comment lines, can not fix %s',filepath); return; end
n_consecutive = find(diff(commentlines)~=1,1,'first');
if isempty(n_consecutive), n_consecutive = numel(commentlines); end % case they are all consecutive
n_last_helpline = commentlines(1)+n_consecutive-1; % consecutive comment lines
% check which lines contain only a comment character
[s,w] = system(sprintf('head -n%d %s | tail -n1',n_last_helpline,filepath));
assert(s==0,'error using head or tail:\n%s',w);
lastline = w;
add_emptycommentline = ~strcmp(strip(lastline),'%'); % add empty comment line if last help line is not just an empty character
indentation = find(lastline=='%',1,'first')-1;
fprintf('adding header at the end of the help section')
n_line_to_insert = n_last_helpline+1;
% total number of lines
[s,w] = system(sprintf('wc -l < %s',filepath)); assert(s==0,'error using wc: \n %s',w);
n_lines = str2double(w);
end_of_file = (n_line_to_insert>n_lines);
for ii=1:numel(desired_header)
my_desired_header = ['% ' ,desired_header{ii}]; % add comment character
% if not already present, add one empty comment line before the header
if add_emptycommentline && ii==1
if ~end_of_file % insert
sedcmd = sprintf('sed -i '''' "%di \\\\\n%*s%%\n" %s',n_line_to_insert,indentation,'',filepath);
else % add after
sedcmd = sprintf('sed -i '''' "%da \\\\\n%*s%%\n" %s',n_line_to_insert-1,indentation,'',filepath);
end
[s,w] = system(sedcmd);
assert(s==0,'error using sed.\nCommand: \n%s\nError:\n%s',sedcmd,w);
n_line_to_insert = n_line_to_insert+1;
end
% add the header
if ~end_of_file % insert before
sedcmd = sprintf('sed -i '''' "%di \\\\\n%*s%s\n" %s',n_line_to_insert,indentation,'',my_desired_header,filepath);
else % add after
sedcmd = sprintf('sed -i '''' "%da \\\\\n%*s%s\n" %s',n_line_to_insert-1,indentation,'',my_desired_header,filepath);
end
n_line_to_insert = n_line_to_insert + 1;
[s,w] = system(sedcmd);
assert(s==0,'error using sed.\nCommand: \n%s\nError:\n%s',sedcmd,w);
end
fprintf('\n');
end