From 8715d0f7e6d34dd42332b8deabf42566eca21a55 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Sun, 18 Dec 2016 16:01:28 -0200 Subject: [PATCH 1/6] ENH: Add minimal classdef support for MOcovMFile Avoid prepending `mocov_line_covered` to: - `classdef`; - `properties` and `methods` section opening statements; - inside the entire `properties` section, since a limited subset of the M-file syntax is allowed. --- MOcov/@MOcovMFile/MOcovMFile.m | 64 ++++++++++++++--- tests/test_MOcovMFile_recognizes_classdef_syntax.m | 81 ++++++++++++++++++++++ ...nes_with_prefix_generate_valid_classdef_files.m | 68 ++++++++++++++++++ 3 files changed, 203 insertions(+), 10 deletions(-) create mode 100644 tests/test_MOcovMFile_recognizes_classdef_syntax.m create mode 100644 tests/test_write_lines_with_prefix_generate_valid_classdef_files.m diff --git a/MOcov/@MOcovMFile/MOcovMFile.m b/MOcov/@MOcovMFile/MOcovMFile.m index 9de6b2d..866314e 100644 --- a/MOcov/@MOcovMFile/MOcovMFile.m +++ b/MOcov/@MOcovMFile/MOcovMFile.m @@ -32,9 +32,14 @@ lines=regexp(s,sprintf('\n'),'split'); - % whether the previous line contained a line continuation, - % i.e. ended with '...' - in_line_continuation=false; + % state variables + in_line_continuation = false; % whether the previous line contained a + % line continuation, i.e. ended with '...' + + inside_class = false; % the file contains a `classdef` statement + + inside_properties = false; % a `properties` section was opened + % but not closed. % see which lines are executable n=numel(lines); @@ -57,12 +62,33 @@ continue; end - executable(k)=~(in_line_continuation || ... - line_is_function_def(line_code_trimmed) || ... - line_is_case_statement(line_code) || ... - line_is_elseif_statement(line_code) || ... - line_is_else_statement(line_code) || ... - line_is_sole_end_statement(line_code_trimmed)); + % Check for statements that ~changes/depends on~ the 'parser' state + classdef_statement = line_is_class_def(line_code_trimmed); + inside_class = inside_class || classdef_statement; + + properties_section = line_opens_properties_section(... + line_code_trimmed, inside_class); + % When a properties section is opened set the inside_properties flag + inside_properties = inside_properties || properties_section; + % When inside_properties is set and an 'end' appears, the section + % is closed. + % This can be considered a hack, since assumes no code that includes + % an `end` is allowed inside properties. + inside_properties = inside_properties && ... + ~line_ends_with_end_statement(line_code_trimmed); + + % classify line + executable(k)=~(... + in_line_continuation || ... + line_is_function_def(line_code_trimmed) || ... + classdef_statement || ... + line_opens_methods_section(line_code_trimmed, inside_class) || ... + inside_properties || ... % Arbitrary code cannot run inside + ... % properties section, just a subset + line_is_case_statement(line_code) || ... + line_is_elseif_statement(line_code) || ... + line_is_else_statement(line_code) || ... + line_is_sole_end_statement(line_code_trimmed)); in_line_continuation=numel(line_code_trimmed)>=3 && ... strcmp(line_code_trimmed(end+(-2:0)),'...'); @@ -84,6 +110,20 @@ tf=~isempty(regexp([newline line],pat,'once')); +function tf=line_is_class_def(line) + % returns true if the line opens a class definition + tf=~isempty(regexp(line,'^\s*classdef\W*','once')); + +function tf=line_opens_methods_section(line, inside_class) + % returns true if the line opens a method section inside class definition + tf=inside_class && ... + ~isempty(regexp(line,'^\s*methods\s*(\([^\(\)]*\))?\s*$','once')); + +function tf=line_opens_properties_section(line, inside_class) + % returns true if the line opens a properties section inside class definition + tf=inside_class && ... + ~isempty(regexp(line,'^\s*properties\s*(\([^\(\)]*\))?\s*$','once')); + function tf=line_is_sole_end_statement(line) % returns true if the string in line is just an end statement tf=isempty(regexprep(line,'([\s,;]|^)?end([\s,;]|$)?','')); @@ -95,4 +135,8 @@ tf=~isempty(regexp(line,'^\s*elseif\W*','once')); function tf=line_is_else_statement(line) - tf=~isempty(regexp(line,'^\s*else\W*','once')); \ No newline at end of file + tf=~isempty(regexp(line,'^\s*else\W*','once')); + +function tf=line_ends_with_end_statement(line) + % returns true if the line has a finishing 'end' + tf=~isempty(regexp(line,'(^|\W)end\s*[,;]?\s*$','once')); diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m new file mode 100644 index 0000000..0624ce2 --- /dev/null +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -0,0 +1,81 @@ +function test_suite = test_MOcovMFile_recognizes_classdef_syntax + initTestSuite; +end + +function fullname = tempfile(filename, contents) + tempfolder = fullfile(tempdir, 'mocov_fixtures'); + [~, ~, ~] = mkdir(tempfolder); + fullname = fullfile(tempfolder, filename); + fid = fopen(fullname, 'w'); + fprintf(fid, contents); + fclose(fid); +end + +function filename = create_classdef + filename = tempfile('AClass.m', [ ... + 'classdef AClass < handle\n', ... + ' properties\n', ... + ' aProp = 1;\n', ... + ' end\n', ... + ' properties (SetAccess = private, Dependent)\n', ... + ' anotherProp;\n', ... + ' end\n', ... + ' methods\n', ... + ' function self = AClass\n', ... + ' fprintf(''hello world!'');\n', ... + ' end\n', ... + ' end\n', ... + ' methods (Access = private)\n', ... + ' function x = aMethod(self)\n', ... + ' fprintf(''hello world!'');\n', ... + ' end\n', ... + ' end\n', ... + 'end\n' ... + ]); +end + +function test_classdef_line_not_executable + mfile = MOcovMFile(create_classdef); + executable_lines = get_lines_executable(mfile); + assert(~executable_lines(1), ... + '`classdef` line is wrongly classified as executable'); +end + +function test_methods_opening_section_not_executable + mfile = MOcovMFile(create_classdef); + + lines = get_lines(mfile); + executable_lines = get_lines_executable(mfile); + method_opening = [8, 13]; + + for l = method_opening + assert(~executable_lines(l), ... + '`%s` line is wrongly classified as executable', lines{l}); + end +end + +function test_method_body_executable + mfile = MOcovMFile(create_classdef); + + lines = get_lines(mfile); + executable_lines = get_lines_executable(mfile); + method_lines = [10, 15]; + + for l = method_lines + assert(executable_lines(l), ... + '`%s` line is wrongly classified as non-executable', lines{l}); + end +end + +function test_properties_line_not_executable + mfile = MOcovMFile(create_classdef); + + lines = get_lines(mfile); + executable_lines = get_lines_executable(mfile); + properties_lines = [2:4, 5:7]; + + for l = properties_lines + assert(~executable_lines(l), ... + '`%s` line is wrongly classified as executable', lines{l}); + end +end diff --git a/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m b/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m new file mode 100644 index 0000000..e0f5032 --- /dev/null +++ b/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m @@ -0,0 +1,68 @@ +function test_suite = test_write_lines_with_prefix_generate_valid_classdef_files + initTestSuite; +end + +function fullname = tempfile(filename, contents) + tempfolder = fullfile(tempdir, 'mocov_fixtures'); + [~, ~, ~] = mkdir(tempfolder); + fullname = fullfile(tempfolder, filename); + fid = fopen(fullname, 'w'); + fprintf(fid, contents); + fclose(fid); +end + +function filename = create_classdef + filename = tempfile('AClass.m', [ ... + 'classdef AClass < handle\n', ... + ' properties\n', ... + ' aProp = 1;\n', ... + ' end\n', ... + ' properties (SetAccess = private, Dependent)\n', ... + ' anotherProp;\n', ... + ' end\n', ... + ' methods\n', ... + ' function self = AClass\n', ... + ' self.anotherProp = 2;\n', ... + ' end\n', ... + ' end\n', ... + ' methods (Access = public)\n', ... + ' function aMethod(self, x)\n', ... + ' self.aProp = x;\n', ... + ' end\n', ... + ' end\n', ... + 'end\n' ... + ]); +end + +function test_generate_valid_file + originalPath = path; % setup + cleaner = onCleanup(@() path(originalPath)); % teardown + + % Given: + % `AClass.m` file with a classdef declaration + filename = create_classdef; + % a folder where mocov will store the decorated files + foldername = fullfile(tempdir, 'mocov_decorated'); + [~,~,~] = mkdir(foldername); + decorated = fullfile(foldername, 'AClass.m'); + % a valid decorator + decorator = @(line_number) ... + sprintf('fprintf(0, ''%s:%d'');', filename, line_number); + + + % When: the decorated file is generated + mfile = MOcovMFile(filename); + write_lines_with_prefix(mfile, decorated, decorator); + + + % Then: the decorated file should have a valid syntax + % Since Octave do not have a linter, run the code to check the syntax. + addpath(foldername); + try + aObject = AClass(); + aObject.aMethod(4); + catch + assert(false, ['Problems when running the decorated file: `%s` ', ... + 'please check for syntax errors.'], decorated); + end +end From 6ab9539d925b798b7c867af7afbfbe1afa7866d8 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 20 Dec 2016 13:05:44 -0200 Subject: [PATCH 2/6] ENH: Improve #9 quality according to revision --- tests/test_MOcovMFile_recognizes_classdef_syntax.m | 86 ++++++++++++++++------ 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m index 0624ce2..bddd7ef 100644 --- a/tests/test_MOcovMFile_recognizes_classdef_syntax.m +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -2,20 +2,42 @@ initTestSuite; end -function fullname = tempfile(filename, contents) - tempfolder = fullfile(tempdir, 'mocov_fixtures'); - [~, ~, ~] = mkdir(tempfolder); - fullname = fullfile(tempfolder, filename); - fid = fopen(fullname, 'w'); +function folderpath = create_tempfolder(foldername) + % Create a folder inside the default temporary director + % and returns it path. + % + % If the folder already exists, do nothing... + + len = length(tempdir); + if length(foldername) >= len && strcmp(foldername(1:len), tempdir) + % Just ignore if foldername already include the tempdir path + folderpath = foldername; + else + folderpath = fullfile(tempdir, foldername); + end + + [unused, unused, unused] = mkdir(folderpath); + % Avoid existing folder warnings by receiving all the 3 outputs of mkdir +end + + +function filepath = create_tempfile(filename, contents) + filepath = fullfile(tempdir, filename); + + % Make sure eventual folder exists + tempfolder = fileparts(filepath); + create_tempfolder(tempfolder); + + fid = fopen(filepath, 'w'); fprintf(fid, contents); fclose(fid); end -function filename = create_classdef - filename = tempfile('AClass.m', [ ... +function filepath = create_classdef + filepath = create_tempfile('AClass.m', [ ... 'classdef AClass < handle\n', ... ' properties\n', ... - ' aProp = 1;\n', ... + ' aProp;\n', ... ' end\n', ... ' properties (SetAccess = private, Dependent)\n', ... ' anotherProp;\n', ... @@ -34,48 +56,68 @@ ]); end +function assertStringContains(text, subtext) + assert(~isempty(strfind(text, subtext)), ... + 'String ''%s'' should contain ''%s'', but it doesn''t.'); +end + function test_classdef_line_not_executable - mfile = MOcovMFile(create_classdef); + tempfile = create_classdef; + teardown = onCleanup(@() delete(tempfile)); + + mfile = MOcovMFile(tempfile); + lines = get_lines(mfile); executable_lines = get_lines_executable(mfile); + + assertStringContains(lines{1}, 'classdef'); assert(~executable_lines(1), ... '`classdef` line is wrongly classified as executable'); end function test_methods_opening_section_not_executable - mfile = MOcovMFile(create_classdef); + tempfile = create_classdef; + teardown = onCleanup(@() delete(tempfile)); + mfile = MOcovMFile(tempfile); lines = get_lines(mfile); executable_lines = get_lines_executable(mfile); method_opening = [8, 13]; - for l = method_opening - assert(~executable_lines(l), ... - '`%s` line is wrongly classified as executable', lines{l}); + for n = method_opening + assertStringContains(lines{n}, 'methods'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); end end function test_method_body_executable - mfile = MOcovMFile(create_classdef); + tempfile = create_classdef; + teardown = onCleanup(@() delete(tempfile)); + mfile = MOcovMFile(tempfile); lines = get_lines(mfile); executable_lines = get_lines_executable(mfile); method_lines = [10, 15]; - for l = method_lines - assert(executable_lines(l), ... - '`%s` line is wrongly classified as non-executable', lines{l}); + for n = method_lines + assertStringContains(lines{n}, 'fprintf'); + assert(executable_lines(n), ... + '`%s` line is wrongly classified as non-executable', lines{n}); end end function test_properties_line_not_executable - mfile = MOcovMFile(create_classdef); + tempfile = create_classdef; + teardown = onCleanup(@() delete(tempfile)); + mfile = MOcovMFile(tempfile); lines = get_lines(mfile); executable_lines = get_lines_executable(mfile); - properties_lines = [2:4, 5:7]; + properties_lines = [3, 6]; - for l = properties_lines - assert(~executable_lines(l), ... - '`%s` line is wrongly classified as executable', lines{l}); + for n = properties_lines + assertStringContains(lines{n}, 'Prop;'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); end end From b0af5e1d9fa81ef2eec4898760986c25e6547983 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 20 Dec 2016 14:03:12 -0200 Subject: [PATCH 3/6] ENH: Improve #9 by merging file tests --- tests/test_MOcovMFile_recognizes_classdef_syntax.m | 65 ++++++++++++++++++--- ...nes_with_prefix_generate_valid_classdef_files.m | 68 ---------------------- 2 files changed, 58 insertions(+), 75 deletions(-) delete mode 100644 tests/test_write_lines_with_prefix_generate_valid_classdef_files.m diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m index bddd7ef..0cb62ec 100644 --- a/tests/test_MOcovMFile_recognizes_classdef_syntax.m +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -33,9 +33,13 @@ fclose(fid); end -function filepath = create_classdef - filepath = create_tempfile('AClass.m', [ ... - 'classdef AClass < handle\n', ... +function filepath = create_classdef(classname) + if nargin < 1 + classname = 'AClass'; + end + + filepath = create_tempfile([classname, '.m'], [ ... + 'classdef ', classname, ' < handle\n', ... ' properties\n', ... ' aProp;\n', ... ' end\n', ... @@ -43,13 +47,13 @@ ' anotherProp;\n', ... ' end\n', ... ' methods\n', ... - ' function self = AClass\n', ... - ' fprintf(''hello world!'');\n', ... + ' function self = ', classname, ' \n', ... + ' fprintf(0, ''hello world!'');\n', ... ' end\n', ... ' end\n', ... - ' methods (Access = private)\n', ... + ' methods (Access = public)\n', ... ' function x = aMethod(self)\n', ... - ' fprintf(''hello world!'');\n', ... + ' fprintf(0, ''hello world!'');\n', ... ' end\n', ... ' end\n', ... 'end\n' ... @@ -62,6 +66,8 @@ function assertStringContains(text, subtext) end function test_classdef_line_not_executable + % Test subject: `MOcovMFile` constructor + tempfile = create_classdef; teardown = onCleanup(@() delete(tempfile)); @@ -75,6 +81,8 @@ function assertStringContains(text, subtext) end function test_methods_opening_section_not_executable + % Test subject: `MOcovMFile` constructor + tempfile = create_classdef; teardown = onCleanup(@() delete(tempfile)); @@ -91,6 +99,8 @@ function assertStringContains(text, subtext) end function test_method_body_executable + % Test subject: `MOcovMFile` constructor + tempfile = create_classdef; teardown = onCleanup(@() delete(tempfile)); @@ -107,6 +117,8 @@ function assertStringContains(text, subtext) end function test_properties_line_not_executable + % Test subject: `MOcovMFile` constructor + tempfile = create_classdef; teardown = onCleanup(@() delete(tempfile)); @@ -121,3 +133,42 @@ function assertStringContains(text, subtext) '`%s` line is wrongly classified as executable', lines{n}); end end + +function test_generate_valid_file + % Test subject: `write_lines_with_prefix` method + + originalPath = path; + pathCleanup = onCleanup(@() path(originalPath)); + + % Given: + + % `AClass.m` file with a classdef declaration + tempfile = create_classdef('AClass'); + tempfileCleanup = onCleanup(@() delete(tempfile)); + + % a folder where mocov will store the decorated files + tempfolder = create_tempfolder(['mocovtest', num2str(randi(99999999999))]); + decorated = fullfile(tempfolder, 'AClass.m'); + tempfolderCleanup = onCleanup(@() rmdir(tempfolder, 's')); + + % a valid decorator + decorator = @(line_number) ... + sprintf('fprintf(0, ''%s:%d'');', tempfile, line_number); + + + % When: the decorated file is generated + mfile = MOcovMFile(tempfile); + write_lines_with_prefix(mfile, decorated, decorator); + + + % Then: the decorated file should have a valid syntax + % Since Octave do not have a linter, run the code to check the syntax. + addpath(tempfolder); + try + aObject = AClass(); + aObject.aMethod(); + catch + assert(false, ['Problems when running the decorated file: `%s` ', ... + 'please check for syntax errors.'], decorated); + end +end diff --git a/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m b/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m deleted file mode 100644 index e0f5032..0000000 --- a/tests/test_write_lines_with_prefix_generate_valid_classdef_files.m +++ /dev/null @@ -1,68 +0,0 @@ -function test_suite = test_write_lines_with_prefix_generate_valid_classdef_files - initTestSuite; -end - -function fullname = tempfile(filename, contents) - tempfolder = fullfile(tempdir, 'mocov_fixtures'); - [~, ~, ~] = mkdir(tempfolder); - fullname = fullfile(tempfolder, filename); - fid = fopen(fullname, 'w'); - fprintf(fid, contents); - fclose(fid); -end - -function filename = create_classdef - filename = tempfile('AClass.m', [ ... - 'classdef AClass < handle\n', ... - ' properties\n', ... - ' aProp = 1;\n', ... - ' end\n', ... - ' properties (SetAccess = private, Dependent)\n', ... - ' anotherProp;\n', ... - ' end\n', ... - ' methods\n', ... - ' function self = AClass\n', ... - ' self.anotherProp = 2;\n', ... - ' end\n', ... - ' end\n', ... - ' methods (Access = public)\n', ... - ' function aMethod(self, x)\n', ... - ' self.aProp = x;\n', ... - ' end\n', ... - ' end\n', ... - 'end\n' ... - ]); -end - -function test_generate_valid_file - originalPath = path; % setup - cleaner = onCleanup(@() path(originalPath)); % teardown - - % Given: - % `AClass.m` file with a classdef declaration - filename = create_classdef; - % a folder where mocov will store the decorated files - foldername = fullfile(tempdir, 'mocov_decorated'); - [~,~,~] = mkdir(foldername); - decorated = fullfile(foldername, 'AClass.m'); - % a valid decorator - decorator = @(line_number) ... - sprintf('fprintf(0, ''%s:%d'');', filename, line_number); - - - % When: the decorated file is generated - mfile = MOcovMFile(filename); - write_lines_with_prefix(mfile, decorated, decorator); - - - % Then: the decorated file should have a valid syntax - % Since Octave do not have a linter, run the code to check the syntax. - addpath(foldername); - try - aObject = AClass(); - aObject.aMethod(4); - catch - assert(false, ['Problems when running the decorated file: `%s` ', ... - 'please check for syntax errors.'], decorated); - end -end From e17637779f4f2651555981b582c37de7adc92c81 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 20 Dec 2016 14:13:09 -0200 Subject: [PATCH 4/6] ENH: Improve #9 by extracting support functions --- Makefile | 4 ++- tests/support/assertStringContains.m | 5 +++ tests/support/create_tempfile.m | 13 ++++++++ tests/support/create_tempfolder.m | 11 +++++++ tests/support/ensure_path_in_tempdir.m | 14 +++++++++ tests/test_MOcovMFile_recognizes_classdef_syntax.m | 36 ---------------------- 6 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 tests/support/assertStringContains.m create mode 100644 tests/support/create_tempfile.m create mode 100644 tests/support/create_tempfolder.m create mode 100644 tests/support/ensure_path_in_tempdir.m diff --git a/Makefile b/Makefile index 1575b9f..9166cb6 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,11 @@ MATLAB?=matlab OCTAVE?=octave TESTDIR=$(CURDIR)/tests +SUPPORTDIR=$(TESTDIR)/support ROOTDIR=$(CURDIR)/MOcov ADDPATH=orig_dir=pwd();cd('$(ROOTDIR)');addpath(pwd);cd(orig_dir) +ADDSUPPORT=orig_dir=pwd();cd('$(SUPPORTDIR)');addpath(pwd);cd(orig_dir) RMPATH=rmpath('$(ROOTDIR)'); SAVEPATH=savepath();exit(0) @@ -49,7 +51,7 @@ ifdef JUNIT_XML_FILE endif -TEST=$(ADDPATH);if(isempty(which('moxunit_runtests'))),error('MOxUnit is required; see https://github.com/MOxUnit/MOxUnit');end;success=moxunit_runtests($(RUNTESTS_ARGS));exit(~success); +TEST=$(ADDPATH);$(ADDSUPPORT);if(isempty(which('moxunit_runtests'))),error('MOxUnit is required; see https://github.com/MOxUnit/MOxUnit');end;success=moxunit_runtests($(RUNTESTS_ARGS));exit(~success); MATLAB_BIN=$(shell which $(MATLAB)) OCTAVE_BIN=$(shell which $(OCTAVE)) diff --git a/tests/support/assertStringContains.m b/tests/support/assertStringContains.m new file mode 100644 index 0000000..2a4dc21 --- /dev/null +++ b/tests/support/assertStringContains.m @@ -0,0 +1,5 @@ + +function assertStringContains(text, subtext) + assert(~isempty(strfind(text, subtext)), ... + 'String ''%s'' should contain ''%s'', but it doesn''t.'); +end diff --git a/tests/support/create_tempfile.m b/tests/support/create_tempfile.m new file mode 100644 index 0000000..152f093 --- /dev/null +++ b/tests/support/create_tempfile.m @@ -0,0 +1,13 @@ +function filepath = create_tempfile(filename, contents) + % Creates a temporary file with the specified content. + + filepath = ensure_path_in_tempdir(filename); + + % Make sure eventual folder exists + tempfolder = fileparts(filepath); + create_tempfolder(tempfolder); + + fid = fopen(filepath, 'w'); + fprintf(fid, contents); + fclose(fid); +end diff --git a/tests/support/create_tempfolder.m b/tests/support/create_tempfolder.m new file mode 100644 index 0000000..d788600 --- /dev/null +++ b/tests/support/create_tempfolder.m @@ -0,0 +1,11 @@ +function folderpath = create_tempfolder(foldername) + % Create a folder inside the default temporary director + % and returns it path. + % + % If the folder already exists, do nothing... + + folderpath = ensure_path_in_tempdir(foldername); + + [unused, unused, unused] = mkdir(folderpath); + % Avoid existing folder warnings by receiving all the 3 outputs of mkdir +end diff --git a/tests/support/ensure_path_in_tempdir.m b/tests/support/ensure_path_in_tempdir.m new file mode 100644 index 0000000..867107d --- /dev/null +++ b/tests/support/ensure_path_in_tempdir.m @@ -0,0 +1,14 @@ +function newpath = ensure_path_in_tempdir(oldpath) + % Check if path start with the tempdir. + % If not, prepend the tempdir to path. + % + % Returns a path that starts with tempdir. + + len = length(tempdir); + if length(oldpath) >= len && strcmp(oldpath(1:len), tempdir) + % Just ignore if oldpath already include the tempdir path + newpath = oldpath; + else + newpath = fullfile(tempdir, oldpath); + end +end diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m index 0cb62ec..a77844e 100644 --- a/tests/test_MOcovMFile_recognizes_classdef_syntax.m +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -2,37 +2,6 @@ initTestSuite; end -function folderpath = create_tempfolder(foldername) - % Create a folder inside the default temporary director - % and returns it path. - % - % If the folder already exists, do nothing... - - len = length(tempdir); - if length(foldername) >= len && strcmp(foldername(1:len), tempdir) - % Just ignore if foldername already include the tempdir path - folderpath = foldername; - else - folderpath = fullfile(tempdir, foldername); - end - - [unused, unused, unused] = mkdir(folderpath); - % Avoid existing folder warnings by receiving all the 3 outputs of mkdir -end - - -function filepath = create_tempfile(filename, contents) - filepath = fullfile(tempdir, filename); - - % Make sure eventual folder exists - tempfolder = fileparts(filepath); - create_tempfolder(tempfolder); - - fid = fopen(filepath, 'w'); - fprintf(fid, contents); - fclose(fid); -end - function filepath = create_classdef(classname) if nargin < 1 classname = 'AClass'; @@ -60,11 +29,6 @@ ]); end -function assertStringContains(text, subtext) - assert(~isempty(strfind(text, subtext)), ... - 'String ''%s'' should contain ''%s'', but it doesn''t.'); -end - function test_classdef_line_not_executable % Test subject: `MOcovMFile` constructor From 08c3ba1364e48e0669a4307bc553acb3b3b5e299 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 20 Dec 2016 14:39:31 -0200 Subject: [PATCH 5/6] ENH: Bring back 'properties' opening check. --- tests/support/assertStringContains.m | 3 +-- tests/test_MOcovMFile_recognizes_classdef_syntax.m | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/support/assertStringContains.m b/tests/support/assertStringContains.m index 2a4dc21..556c752 100644 --- a/tests/support/assertStringContains.m +++ b/tests/support/assertStringContains.m @@ -1,5 +1,4 @@ - function assertStringContains(text, subtext) assert(~isempty(strfind(text, subtext)), ... - 'String ''%s'' should contain ''%s'', but it doesn''t.'); + 'String ''%s'' should contain ''%s'', but it doesn''t.', text, subtext); end diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m index a77844e..27e8bab 100644 --- a/tests/test_MOcovMFile_recognizes_classdef_syntax.m +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -89,9 +89,16 @@ mfile = MOcovMFile(tempfile); lines = get_lines(mfile); executable_lines = get_lines_executable(mfile); - properties_lines = [3, 6]; + properties_opening = [2, 5]; + properties_body = [3, 6]; - for n = properties_lines + for n = properties_opening + assertStringContains(lines{n}, 'properties'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); + end + + for n = properties_body; assertStringContains(lines{n}, 'Prop;'); assert(~executable_lines(n), ... '`%s` line is wrongly classified as executable', lines{n}); From 25df341892ab8d406eda8bd1d751d9742baa83b8 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Sat, 24 Dec 2016 13:01:48 +0000 Subject: [PATCH 6/6] ENH: Remove 'support' dir and tempfolder (#9) For now helper functions for classdef syntax check do not need to be shared, so them can go back to the test file itself. Tempfolder usage can be avoided to make test simpler. Additionally make whitespace consistent in test file. OBS: The function name assertSringContains was written using camelCase to be consistent with MOxUnit assertion helpers. --- Makefile | 4 +- tests/support/assertStringContains.m | 4 -- tests/support/create_tempfile.m | 13 ---- tests/support/create_tempfolder.m | 11 ---- tests/support/ensure_path_in_tempdir.m | 14 ---- tests/test_MOcovMFile_recognizes_classdef_syntax.m | 76 +++++++++++++--------- 6 files changed, 45 insertions(+), 77 deletions(-) delete mode 100644 tests/support/assertStringContains.m delete mode 100644 tests/support/create_tempfile.m delete mode 100644 tests/support/create_tempfolder.m delete mode 100644 tests/support/ensure_path_in_tempdir.m diff --git a/Makefile b/Makefile index 9166cb6..1575b9f 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,9 @@ MATLAB?=matlab OCTAVE?=octave TESTDIR=$(CURDIR)/tests -SUPPORTDIR=$(TESTDIR)/support ROOTDIR=$(CURDIR)/MOcov ADDPATH=orig_dir=pwd();cd('$(ROOTDIR)');addpath(pwd);cd(orig_dir) -ADDSUPPORT=orig_dir=pwd();cd('$(SUPPORTDIR)');addpath(pwd);cd(orig_dir) RMPATH=rmpath('$(ROOTDIR)'); SAVEPATH=savepath();exit(0) @@ -51,7 +49,7 @@ ifdef JUNIT_XML_FILE endif -TEST=$(ADDPATH);$(ADDSUPPORT);if(isempty(which('moxunit_runtests'))),error('MOxUnit is required; see https://github.com/MOxUnit/MOxUnit');end;success=moxunit_runtests($(RUNTESTS_ARGS));exit(~success); +TEST=$(ADDPATH);if(isempty(which('moxunit_runtests'))),error('MOxUnit is required; see https://github.com/MOxUnit/MOxUnit');end;success=moxunit_runtests($(RUNTESTS_ARGS));exit(~success); MATLAB_BIN=$(shell which $(MATLAB)) OCTAVE_BIN=$(shell which $(OCTAVE)) diff --git a/tests/support/assertStringContains.m b/tests/support/assertStringContains.m deleted file mode 100644 index 556c752..0000000 --- a/tests/support/assertStringContains.m +++ /dev/null @@ -1,4 +0,0 @@ -function assertStringContains(text, subtext) - assert(~isempty(strfind(text, subtext)), ... - 'String ''%s'' should contain ''%s'', but it doesn''t.', text, subtext); -end diff --git a/tests/support/create_tempfile.m b/tests/support/create_tempfile.m deleted file mode 100644 index 152f093..0000000 --- a/tests/support/create_tempfile.m +++ /dev/null @@ -1,13 +0,0 @@ -function filepath = create_tempfile(filename, contents) - % Creates a temporary file with the specified content. - - filepath = ensure_path_in_tempdir(filename); - - % Make sure eventual folder exists - tempfolder = fileparts(filepath); - create_tempfolder(tempfolder); - - fid = fopen(filepath, 'w'); - fprintf(fid, contents); - fclose(fid); -end diff --git a/tests/support/create_tempfolder.m b/tests/support/create_tempfolder.m deleted file mode 100644 index d788600..0000000 --- a/tests/support/create_tempfolder.m +++ /dev/null @@ -1,11 +0,0 @@ -function folderpath = create_tempfolder(foldername) - % Create a folder inside the default temporary director - % and returns it path. - % - % If the folder already exists, do nothing... - - folderpath = ensure_path_in_tempdir(foldername); - - [unused, unused, unused] = mkdir(folderpath); - % Avoid existing folder warnings by receiving all the 3 outputs of mkdir -end diff --git a/tests/support/ensure_path_in_tempdir.m b/tests/support/ensure_path_in_tempdir.m deleted file mode 100644 index 867107d..0000000 --- a/tests/support/ensure_path_in_tempdir.m +++ /dev/null @@ -1,14 +0,0 @@ -function newpath = ensure_path_in_tempdir(oldpath) - % Check if path start with the tempdir. - % If not, prepend the tempdir to path. - % - % Returns a path that starts with tempdir. - - len = length(tempdir); - if length(oldpath) >= len && strcmp(oldpath(1:len), tempdir) - % Just ignore if oldpath already include the tempdir path - newpath = oldpath; - else - newpath = fullfile(tempdir, oldpath); - end -end diff --git a/tests/test_MOcovMFile_recognizes_classdef_syntax.m b/tests/test_MOcovMFile_recognizes_classdef_syntax.m index 27e8bab..5157e68 100644 --- a/tests/test_MOcovMFile_recognizes_classdef_syntax.m +++ b/tests/test_MOcovMFile_recognizes_classdef_syntax.m @@ -2,9 +2,24 @@ initTestSuite; end +function assertStringContains(text, subtext) + assert(~isempty(strfind(text, subtext)), ... + 'String ''%s'' should contain ''%s'', but it doesn''t.', text, subtext); +end + +function filepath = create_tempfile(filename, contents) + % Creates a temporary file with the specified content. + + filepath = fullfile(tempdir, filename); + fid = fopen(filepath, 'w'); + fprintf(fid, contents); + fclose(fid); +end + function filepath = create_classdef(classname) if nargin < 1 - classname = 'AClass'; + % Use a random name to ensure uniqueness + classname = char(64 + ceil(26*rand(1, 20))); end filepath = create_tempfile([classname, '.m'], [ ... @@ -56,9 +71,9 @@ method_opening = [8, 13]; for n = method_opening - assertStringContains(lines{n}, 'methods'); - assert(~executable_lines(n), ... - '`%s` line is wrongly classified as executable', lines{n}); + assertStringContains(lines{n}, 'methods'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); end end @@ -74,9 +89,9 @@ method_lines = [10, 15]; for n = method_lines - assertStringContains(lines{n}, 'fprintf'); - assert(executable_lines(n), ... - '`%s` line is wrongly classified as non-executable', lines{n}); + assertStringContains(lines{n}, 'fprintf'); + assert(executable_lines(n), ... + '`%s` line is wrongly classified as non-executable', lines{n}); end end @@ -93,53 +108,50 @@ properties_body = [3, 6]; for n = properties_opening - assertStringContains(lines{n}, 'properties'); - assert(~executable_lines(n), ... - '`%s` line is wrongly classified as executable', lines{n}); + assertStringContains(lines{n}, 'properties'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); end for n = properties_body; - assertStringContains(lines{n}, 'Prop;'); - assert(~executable_lines(n), ... - '`%s` line is wrongly classified as executable', lines{n}); + assertStringContains(lines{n}, 'Prop;'); + assert(~executable_lines(n), ... + '`%s` line is wrongly classified as executable', lines{n}); end end function test_generate_valid_file % Test subject: `write_lines_with_prefix` method - originalPath = path; - pathCleanup = onCleanup(@() path(originalPath)); + original_path = path; + path_cleanup = onCleanup(@() path(original_path)); % Given: % `AClass.m` file with a classdef declaration - tempfile = create_classdef('AClass'); - tempfileCleanup = onCleanup(@() delete(tempfile)); - - % a folder where mocov will store the decorated files - tempfolder = create_tempfolder(['mocovtest', num2str(randi(99999999999))]); - decorated = fullfile(tempfolder, 'AClass.m'); - tempfolderCleanup = onCleanup(@() rmdir(tempfolder, 's')); - + classname = ['AClass', char(64 + ceil(26*rand(1, 20)))]; + tempfile = create_classdef(classname); + teardown = onCleanup(@() delete(tempfile)); % a valid decorator decorator = @(line_number) ... - sprintf('fprintf(0, ''%s:%d'');', tempfile, line_number); - + sprintf('fprintf(0, ''%s:%d'');', tempfile, line_number); % When: the decorated file is generated mfile = MOcovMFile(tempfile); - write_lines_with_prefix(mfile, decorated, decorator); - + write_lines_with_prefix(mfile, tempfile, decorator); + % ^ Here we just overwrite the original file, because we don't use it. + % In the real word, the new file should be saved to a + % different folder. % Then: the decorated file should have a valid syntax % Since Octave do not have a linter, run the code to check the syntax. - addpath(tempfolder); + addpath(tempdir); try - aObject = AClass(); - aObject.aMethod(); + constructor = str2func(classname); + aObject = constructor(); + aObject.aMethod(); catch - assert(false, ['Problems when running the decorated file: `%s` ', ... - 'please check for syntax errors.'], decorated); + assert(false, ['Problems when running the decorated file: `%s` ', ... + 'please check for syntax errors.'], decorated); end end