-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtester.m
112 lines (103 loc) · 3.07 KB
/
tester.m
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
%% tester: Automatically run all unit tests.
%
% tester will run the unit tests, and report as to which ones passed.
%
% S = tester() will run all unit tests, and return structure array S with
% the test name and its status
%
% S = tester(T1, T2, ...) will run the specified unit tests, specified as
% either character vectors or function handles, and their status will be in
% array S, wich has the same number of elements as the number of inputs.
%
% tester(___) will do the same as above, but will instead print the results
% onto the display
%
%%% Remarks
%
% Test names are the name of the test function, with or without the .m.
%
%%% Exceptions
%
% If a function evaluates with an error, the exception is caused and given
% as the reason
function status = tester(varargin)
% change to our current dir for testing;
orig = cd(fileparts(mfilename('fullpath')));
generateTests();
cleaner = onCleanup(@()(clean(orig)));
if isempty(varargin)
inputs = dir(['.' filesep 'unitTests' filesep '*_test.m']);
inputs = {inputs.name};
else
inputs = varargin;
end
% add the right path
isParallel = ~isempty(gcp('nocreate'));
addpath(genpath(pwd));
handles = cellfun(@converter, inputs, 'uni', false);
status = struct('name', cell(1, numel(handles)), ...
'status', cell(1, numel(handles)), ...
'reason', cell(1, numel(handles)));
for h = numel(handles):-1:1
% set up call
fun = handles{h};
status(h).name = strtok(func2str(fun), '_');
if isParallel
workers(h) = parfeval(@runTest, 2, fun);
else
[status(h).status, status(h).reason] = runTest(fun);
end
end
if isParallel
while ~all([workers.Read])
[idx, s, r] = workers.fetchNext();
status(idx).status = s;
status(idx).reason = r;
end
end
if nargout == 0
% for each test, print out
for t = 1:numel(status)
if status(t).status
fprintf(1, 'Test %s: Passed\n', ...
status(t).name);
else
fprintf(2, 'Test %s: Failed - %s\n', ...
status(t).name, ...
status(t).reason);
end
end
clear('status');
end
end
function [passed, msg] = runTest(fun)
close('all', 'force');
try
[passed, msg] = fun();
catch e
passed = false;
msg = sprintf('Test Error: %s (%s)', e.identifier, e.message);
end
end
function h = converter(inp)
if isstring(inp)
inp = char(inp);
end
if ischar(inp)
if endsWith(inp, '.m')
inp = inp(1:end-2);
end
h = str2func(inp);
elseif isa(inp, 'function_handle')
h = inp;
else
throw(MException('TESTER:invalidInput', ...
sprintf('Expected a string or function_handle; got %s', ...
class(inp))));
end
end
function clean(orig)
% delete p codes
delete(['.' filesep 'unitTests' filesep '*_soln.p']);
cd(orig);
end