Auswertung Experiment

Database tüddelei
DBHanlder läuft gut für DIESE Datanbank struktur...
App begonnen aber weit entfernt von gutem Stand
This commit is contained in:
sioe
2024-11-15 16:51:37 +01:00
parent 553ed19b9f
commit 397cfa61dd
219 changed files with 584 additions and 854 deletions

View File

@@ -0,0 +1,36 @@
function [formatted, OSType, OSVersion] = OSVersion()
% determines the OS type and its (kernel) version number
if ismac
OSType = 'Mac OS';
[dummy, OSVersion] = system('sw_vers -productVersion'); %#ok
% Output like "10.10.4" for OS X Yosemite
elseif ispc
OSType = 'Windows';
[dummy, rawVersion] = system('ver'); %#ok
% Output like "Microsoft Windows [Version 6.3.9600]" for Win8.1
pattern = '(?<=Version )[0-9.]+';
OSVersion = regexpi(rawVersion, pattern, 'match', 'once');
elseif isunix
[dummy, OSType] = system('uname -s'); %#ok
% This returns the kernal name
% e.g. "Linux" on Linux, "Darwin" on Mac, "SunOS" on Solaris
[dummy, OSVersion] = system('uname -r'); %#ok
% Returns the kernel version. Many Linux distributions
% include an identifier, e.g. "4.0.7-2-ARCH" on Arch Linux
% TODO: also use `lsb_release` in Linux for distro info
else
warning('OSVersion:UnknownOS', 'Could not recognize OS.');
OSType = 'Unknown OS';
OSVersion = '';
end
EOL = sprintf('\n');
OSType = strrep(OSType, EOL, '');
OSVersion = strrep(OSVersion, EOL, '');
formatted = strtrim([OSType ' ' OSVersion]);
end

View File

@@ -0,0 +1,74 @@
function SM = StreamMaker()
% StreamMaker (Factory for fie/input/output Streams)
%
% A StreamMaker can make Stream PseudoObjects based on either
% an "fid" or "filename" (and extra arguments for `fopen`).
% The StreamMaker also contains a method `isStream` to validate whether
% the value passed is a valid stream specifier.
%
% Usage
%
% SM = StreamMaker;
%
% Stream = SM.make(fid)
% Stream = SM.make(filename, ...)
%
% This returns a PseudoObject Stream with the following properties:
% - name: (file) name of the stream
% - fid: handle (fid) of the stream
%
% and methods:
% - print: prints to the stream, i.e. fprintf
% - close: closes the stream, i.e. fclose
%
% It may also contain a field to automatically close the Stream when it goes
% out of scope.
%
SM = PseudoObject('StreamMaker', ...
'isStream', @isStream, ...
'make', @constructStream);
end
function PseudoObj = PseudoObject(T, varargin)
% construct a Pseudo-Object with type T (no other fields yet)
PseudoObj = struct('Type', T, varargin{:});
end
function bool = isStream(value)
bool = ischar(value) || ismember(value, [1,2,fopen('all')]);
%TODO: allow others kinds of streams
% Stream -> clipboard (write on close)
% Stream -> string variable
% e.g. a quick-and-dirty way would be to write the file to `tempname`
% putting a flag to read that file back upon completion.
end
function Stream = constructStream(streamSpecifier, varargin)
% this is the actual constructor of a stream
if ~isStream(streamSpecifier)
error('StreamMaker:NotAStream', 'Invalid stream specifier "%s"', ...
streamSpecifier);
end
Stream = PseudoObject('Stream');
closeAfterUse = false;
if ischar(streamSpecifier)
Stream.name = streamSpecifier;
Stream.fid = fopen(Stream.name, varargin{:});
closeAfterUse = true;
elseif isnumeric(streamSpecifier)
Stream.fid = streamSpecifier;
Stream.name = fopen(Stream.fid);
end
if Stream.fid == -1
error('Stream:InvalidStream', ...
'Unable to create stream "%s"!', streamSpecifier);
end
Stream.print = @(varargin) fprintf(Stream.fid, varargin{:});
Stream.close = @() fclose(Stream.fid);
if closeAfterUse
Stream.closeAfterUse = onCleanup(Stream.close);
end
end

View File

@@ -0,0 +1,47 @@
function [formatted,treeish] = VersionControlIdentifier()
% This function gives the (git) commit ID of matlab2tikz
%
% This assumes the standard directory structure as used by Nico's master branch:
% SOMEPATH/src/matlab2tikz.m with a .git directory in SOMEPATH.
%
% The HEAD of that repository is determined from file system information only
% by following dynamic references (e.g. ref:refs/heds/master) in branch files
% until an absolute commit hash (e.g. 1a3c9d1...) is found.
% NOTE: Packed branch references are NOT supported by this approach
MAXITER = 10; % stop following dynamic references after a while
formatted = '';
REFPREFIX = 'ref:';
isReference = @(treeish)(any(strfind(treeish, REFPREFIX)));
treeish = [REFPREFIX 'HEAD'];
try
% get the matlab2tikz directory
privateDir = fileparts(mfilename('fullpath'));
gitDir = fullfile(privateDir,'..','..','.git');
nIter = 1;
while isReference(treeish)
refName = treeish(numel(REFPREFIX)+1:end);
branchFile = fullfile(gitDir, refName);
if exist(branchFile, 'file') && nIter < MAXITER
% The FID is reused in every iteration, so `onCleanup` cannot
% be used to `fclose(fid)`. But since there is very little that
% can go wrong in a single `fscanf`, it's probably best to leave
% this part as it is for the time being.
fid = fopen(branchFile,'r');
treeish = fscanf(fid,'%s');
fclose(fid);
nIter = nIter + 1;
else % no branch file or iteration limit reached
treeish = '';
return;
end
end
catch %#ok
treeish = '';
end
if ~isempty(treeish)
formatted = [' Commit & ' treeish ' \\\\ \n'];
end
%TODO: do the formatting somewhere else!
end

View File

@@ -0,0 +1,35 @@
function hash = calculateMD5Hash(filename)
% CALCULATEMD5HASH calculate a MD5 hash of a file
%
% This functionality is built-in into Octave but uses Java in MATLAB.
switch getEnvironment
case 'Octave'
hash = md5sum(filename);
case 'MATLAB'
% There are some MD5 implementations in MATLAB, but those
% tend to be slow and licensing is unclear.
% Rolling our own implementation is unwanted, especially since this
% is a cryptographic hash, even though its security has been
% broken. Instead we make use of the Java libraries.
% Unless the "-nojvm" flag is specified, this should work well.
MD5 = java.security.MessageDigest.getInstance('MD5');
% Open the file
fid = fopen(filename, 'r');
% Make sure fid is closed
finally_close = onCleanup(@()fclose(fid));
% Faster file digest based on code by Jan Simon as in
% http://www.mathworks.com/matlabcentral/fileexchange/31272-datahash
data = fread(fid, '*uint8');
MD5.update(data);
hash = reshape(dec2hex(typecast(MD5.digest(),'uint8')).', 1, 32);
end
hash = lower(hash);
end

View File

@@ -0,0 +1,19 @@
function cleanFiles(cleanBefore)
% clean output files in ./tex using make
%FIXME: this file appears to be unused (but it is useful)
%FIXME: adapt this file to take the output directory into account
if cleanBefore && exist(fullfile('tex','Makefile'),'file')
fprintf(1, 'Cleaning output files...\n');
cwd = pwd;
try
cd('tex');
[exitCode, output] = system('make distclean');
fprintf(1,'%s\n', output);
assert(exitCode==0, 'Exit code 0 means correct execution');
catch
% This might happen when make is not present
fprintf(2, '\tNot completed succesfully\n\n');
end
cd(cwd);
end
end

View File

@@ -0,0 +1,4 @@
function nErrors = countNumberOfErrors(status)
% counts the number of errors in a status cell array
nErrors = sum(hasTestFailed(status));
end

View File

@@ -0,0 +1,4 @@
function stage = emptyStage()
% constructs an empty (workflow) stage struct
stage = struct('message', '', 'error' , false);
end

View File

@@ -0,0 +1,24 @@
function defaultStatus = emptyStatus(testsuite, testNumber)
% constructs an empty status struct
defaultStatus = struct(...
'function', '', ...
'description', '',...
'testsuite', testsuite ,...
'index', testNumber, ...
'issues', [],...
'unreliable', false, ...
'skip', false, ... % skipped this test?
'closeall', false, ... % call close all after?
'extraOptions', {cell(0)}, ...
'extraCleanfigureOptions',{cell(0)}, ...
'plotStage', emptyStage(), ...
'saveStage', emptyStage(), ...
'tikzStage', emptyStage(), ...
'hashStage', emptyStage() ...
);
% for reliable tests explicitly define width and height, see #659
% TODO: Remove explicitly setting this option.
% After #641 is merged, this might be not needed anyhow.
defaultStatus.extraCleanfigureOptions = {'targetResolution', [1000,500]};
end

View File

@@ -0,0 +1,41 @@
function [stage, errorHasOccurred] = errorHandler(e)
% common error handler code: save and print to console
errorHasOccurred = true;
stage = emptyStage();
stage.message = format_error_message(e);
stage.error = errorHasOccurred;
disp_error_message(stage.message);
end
% ==============================================================================
function msg = format_error_message(e)
msg = '';
if ~isempty(e.message)
msg = sprintf('%serror: %s\n', msg, e.message);
end
if ~isempty(e.identifier)
if strfind(lower(e.identifier),'testmatlab2tikz:')
% When "errors" occur in the test framework, i.e. a hash mismatch
% or no hash provided, there is no need to be very verbose.
% So we don't return the msgid and the stack trace in those cases!
return % only return the message
end
msg = sprintf('%serror: %s\n', msg, e.identifier);
end
if ~isempty(e.stack)
msg = sprintf('%serror: called from:\n', msg);
for ee = e.stack(:)'
msg = sprintf('%serror: %s at line %d, in function %s\n', ...
msg, ee.file, ee.line, ee.name);
end
end
end
% ==============================================================================
function disp_error_message(msg)
stderr = 2;
% The error message should not contain any more escape sequences and
% hence can be output literally to stderr.
fprintf(stderr, '%s', msg);
end
% ==============================================================================

View File

@@ -0,0 +1,16 @@
function errorOccurred = errorHasOccurred(status)
% determines whether an error has occurred from a status struct OR cell array
% of status structs
errorOccurred = false;
if iscell(status)
for iStatus = 1:numel(status)
errorOccurred = errorOccurred || errorHasOccurred(status{iStatus});
end
else
stages = getStagesFromStatus(status);
for iStage = 1:numel(stages)
thisStage = status.(stages{iStage});
errorOccurred = errorOccurred || thisStage.error;
end
end
end

View File

@@ -0,0 +1,34 @@
function [status] = execute_hash_stage(status, ipp)
% test stage: check recorded hash checksum
calculated = '';
expected = '';
try
expected = getReferenceHash(status, ipp);
calculated = calculateMD5Hash(status.tikzStage.texFile);
% do the actual check
if ~strcmpi(expected, calculated)
% throw an error to signal the testing framework
error('testMatlab2tikz:HashMismatch', ...
'The hash "%s" does not match the reference hash "%s"', ...
calculated, expected);
end
catch %#ok
e = lasterror('reset'); %#ok
[status.hashStage] = errorHandler(e);
end
status.hashStage.expected = expected;
status.hashStage.found = calculated;
end
% ==============================================================================
function hash = getReferenceHash(status, ipp)
% retrieves a reference hash from a hash table
% WARNING: do not make `hashTable` persistent, since this is slower
hashTable = loadHashTable(ipp.Results.testsuite);
if isfield(hashTable.contents, status.function)
hash = hashTable.contents.(status.function);
else
hash = '';
end
end

View File

@@ -0,0 +1,45 @@
function [status] = execute_plot_stage(defaultStatus, ipp)
% plot a test figure
testsuite = ipp.Results.testsuite;
testNumber = defaultStatus.index;
% open a window
fig_handle = figure('visible',ipp.Results.figureVisible);
errorHasOccurred = false;
% plot the figure
try
status = testsuite(testNumber);
catch %#ok
e = lasterror('reset'); %#ok
status.description = '\textcolor{red}{Error during plot generation.}';
[status.plotStage, errorHasOccurred] = errorHandler(e);
% Automaticall mark the test as unreliable
%
% Since metadata is not set in this case, also stat.unreliable is
% not returned. So ideally, we should
% FIXME: implement #484 to get access to the meta data
% but we can work around this issue by forcefully setting that value.
% The rationale for setting this to true:
% - the plot part is not the main task of M2T
% (so breaking a single test is less severe in this case),
% - if the plotting fails, the test is not really reliable anyway,
% - this allows to get full green on Travis.
status.unreliable = true;
end
status = fillStruct(status, defaultStatus);
if isempty(status.function)
allFuncs = testsuite(0);
status.function = func2str(allFuncs{testNumber});
end
status.plotStage.fig_handle = fig_handle;
if status.skip || errorHasOccurred
close(fig_handle);
end
end

View File

@@ -0,0 +1,63 @@
function [status] = execute_save_stage(status, ipp)
% save stage: saves the figure to EPS/PDF depending on env
testNumber = status.index;
basepath = fullfile(ipp.Results.output,'data','reference');
reference_eps = fullfile(basepath, sprintf('test%d-reference.eps', testNumber));
reference_pdf = fullfile(basepath, sprintf('test%d-reference.pdf', testNumber));
% the reference below is for inclusion in LaTeX! Use UNIX conventions!
reference_fig = sprintf('data/reference/test%d-reference', testNumber);
% Save reference output as PDF
try
switch getEnvironment
case 'MATLAB'
% MATLAB does not generate properly cropped PDF files.
% So, we generate EPS files that are converted later on.
print(gcf, '-depsc2', reference_eps);
fixLineEndingsInWindows(reference_eps);
case 'Octave'
% In Octave, figures are properly cropped when using print().
print(reference_pdf, '-dpdf', '-S415,311', '-r150');
pause(1.0)
otherwise
error('matlab2tikz:UnknownEnvironment', ...
'Unknown environment. Need MATLAB(R) or GNU Octave.')
end
catch %#ok
e = lasterror('reset'); %#ok
[status.saveStage] = errorHandler(e);
end
status.saveStage.epsFile = reference_eps;
status.saveStage.pdfFile = reference_pdf;
status.saveStage.texReference = reference_fig;
end
% ==============================================================================
function fixLineEndingsInWindows(filename)
% On R2014b Win, line endings in .eps are Unix style (LF) instead of Windows
% style (CR+LF). This causes problems in the MikTeX `epstopdf` for some files
% as dicussed in:
% * https://github.com/matlab2tikz/matlab2tikz/issues/370
% * http://tex.stackexchange.com/questions/208179
if ispc
fid = fopen(filename,'r+');
finally_fclose_fid = onCleanup(@() fclose(fid));
testline = fgets(fid);
CRLF = sprintf('\r\n');
endOfLine = testline(end-1:end);
if ~strcmpi(endOfLine, CRLF)
endOfLine = testline(end); % probably an LF
% Rewind, read the whole
fseek(fid,0,'bof');
str = fread(fid,'*char')';
% Replace, overwrite and close
str = strrep(str, endOfLine, CRLF);
fseek(fid,0,'bof');
fprintf(fid,'%s',str);
end
end
end

View File

@@ -0,0 +1,43 @@
function [status] = execute_tikz_stage(status, ipp)
% test stage: TikZ file generation
testNumber = status.index;
datapath = fullfile(ipp.Results.output,'data','converted');
gen_tex = fullfile(datapath, sprintf('test%d-converted.tex', testNumber));
% the value below is for inclusion into LaTeX report! Use UNIX convention.
gen_pdf = sprintf('data/converted/test%d-converted.pdf', testNumber);
cleanfigure_time = NaN;
m2t_time = NaN;
% now, test matlab2tikz
try
%TODO: remove this once text removal has been removed
oldWarn = warning('off','cleanfigure:textRemoval');
cleanfigure_time = tic;
cleanfigure(status.extraCleanfigureOptions{:});
cleanfigure_time = toc(cleanfigure_time);
warning(oldWarn);
m2t_time = tic;
matlab2tikz('filename', gen_tex, ...
'showInfo', false, ...
'checkForUpdates', false, ...
'dataPath', datapath, ...
'standalone', true, ...
ipp.Results.extraOptions{:}, ...
status.extraOptions{:} ...
);
m2t_time = toc(m2t_time);
catch %#ok
e = lasterror('reset'); %#ok
% Remove (corrupted) output file. This is necessary to avoid that the
% Makefile tries to compile it and fails.
delete(gen_tex)
[status.tikzStage] = errorHandler(e);
end
status.tikzStage.texFile = gen_tex;
status.tikzStage.pdfFile = gen_pdf;
status.tikzStage.m2t_time = m2t_time;
status.tikzStage.cleanfigure_time = cleanfigure_time;
end

View File

@@ -0,0 +1,15 @@
function [status] = execute_type_stage(status, ipp)
try
filename = status.tikzStage.texFile;
stream = 1; % stdout
if errorHasOccurred(status) && exist(filename, 'file')
shortname = strrep(filename, m2troot, '$(M2TROOT)');
fprintf(stream, '\n%%%%%%%% BEGIN FILE "%s" %%%%%%%%\n', shortname);
type(filename);
fprintf(stream, '\n%%%%%%%% END FILE "%s" %%%%%%%%\n', shortname);
end
catch
e = lasterror('reset');
[status.typeStage] = errorHandler(e);
end
end

View File

@@ -0,0 +1,10 @@
function [status] = fillStruct(status, defaultStatus)
% fills non-existant fields of |data| with those of |defaultData|
fields = fieldnames(defaultStatus);
for iField = 1:numel(fields)
field = fields{iField};
if ~isfield(status,field)
status.(field) = defaultStatus.(field);
end
end
end

View File

@@ -0,0 +1,25 @@
function [env, versionString] = getEnvironment()
% Determine environment (Octave, MATLAB) and version string
% TODO: Unify private `getEnvironment` functions
persistent cache
if isempty(cache)
isOctave = exist('OCTAVE_VERSION', 'builtin') ~= 0;
if isOctave
env = 'Octave';
versionString = OCTAVE_VERSION;
else
env = 'MATLAB';
vData = ver(env);
versionString = vData.Version;
end
% store in cache
cache.env = env;
cache.versionString = versionString;
else
env = cache.env;
versionString = cache.versionString;
end
end

View File

@@ -0,0 +1,5 @@
function stages = getStagesFromStatus(status)
% retrieves the different (names of) stages of a status struct
fields = fieldnames(status);
stages = fields(cellfun(@(f) ~isempty(strfind(f,'Stage')), fields));
end

View File

@@ -0,0 +1,13 @@
function bool = hasTestFailed(status)
% returns true when the test has failed
if iscell(status) % allow for vectorization of the call
bool = cellfun(@hasTestFailed, status, 'UniformOutput', true);
else
stages = getStagesFromStatus(status);
bool = false;
for jStage = 1:numel(stages)
bool = bool || status.(stages{jStage}).error;
end
end
end

View File

@@ -0,0 +1,55 @@
function filename = hashTableName(suite)
% determines the file name of a hash table
%
% The MD5 file is assumed to be in the same directory as the test suite.
% It has a file name "$SUITE.$ENV.$VER.md5"
% where the following fields are filled:
% $ENV: the environment (either "MATLAB" or "Octave")
% $VER: the version (e.g. "3.8.0" for Octave, "8.3" for MATLAB 2014a)
% $SUITE: the name (and path) of the test suite
%
% For the $VER-part, a fall-back mechanism is present that prefers the exact
% version but will use the closest available file if such file does not
% exist.
[pathstr,name, ext] = fileparts(which(func2str(suite)));
[env, version] = getEnvironment();
ext = sprintf('.%s.%s.md5', env, version);
relFilename = [name ext];
filename = fullfile(pathstr, relFilename);
if ~exist(filename,'file')
% To avoid having to create a file for each release of the environment,
% also other versions are tried. The file for different releases are checked
% in the following order:
% 1. the currently running version (handled above!)
% 2. the newest older version (e.g. use R2014b's file in R2015a)
% 3. the oldest newer version (e.g. use R2014a's file in R2013a)
pattern = sprintf('%s.%s.*.md5', name, env);
candidates = dir(fullfile(pathstr, pattern));
% We just need the file names.
filenames = arrayfun(@(c)c.name, candidates, 'UniformOutput', false);
% Add the expected version to the results, and sort the names by
% version (this is the same as alphabetically).
filenames = sort([filenames; {relFilename}]);
nFiles = numel(filenames);
iCurrent = find(ismember(filenames, relFilename));
% determine the fall-back candidates:
iNewestOlder = iCurrent - 1;
iOldestNewer = iCurrent + 1;
inRange = @(idx)(idx <= nFiles && idx >= 1);
if inRange(iNewestOlder)
% use the newest older version
relFilename = filenames{iNewestOlder};
elseif inRange(iOldestNewer)
% use the oldest newer version
relFilename = filenames{iOldestNewer};
else
% use the exact version anyhow
end
filename = fullfile(pathstr, relFilename);
end
end

View File

@@ -0,0 +1,99 @@
function [orig] = initializeGlobalState()
% Initialize global state. Set working directory and various properties of
% the graphical root to ensure reliable output of the ACID testsuite.
% See #542 and #552
%
% 1. Working directory
% 2. Bring get(0,'Default') in line with get(0,'Factory')
% 3. Set specific properties, required by matlab2tikz
fprintf('Initialize global state...\n');
orig = struct();
%--- Extract user defined default properties and set factory state
default = get(0,'Default');
factory = get(0,'Factory');
f = fieldnames(default); % fields of user's default state
for i = 1:length(f)
factory_property_name = strrep(f{i},'default','factory');
factory_property_value = factory.(factory_property_name);
orig.(f{i}).val = ...
swapPropertyState(0, f{i}, factory_property_value);
end
%--- Define desired global state properties
% defaultAxesColorOrder: on HG1 'default' and 'factory' differ and
% HG1 differs from HG2. Consequently use HG2 colors (the new standard).
new.defaultAxesColorOrder.val = [0.000 0.447 0.741; ...
0.850 0.325 0.098; ...
0.929 0.694 0.125; ...
0.494 0.184 0.556; ...
0.466 0.674 0.188; ...
0.301 0.745 0.933; ...
0.635 0.0780 0.184];
new.defaultAxesColorOrder.ignore= false;
% defaultFigurePosition: width and height influence cleanfigure() and
% the number/location of axis ticks
new.defaultFigurePosition.val = [300,200,560,420];
new.defaultFigurePosition.ignore= false;
% ScreenPixelsPerInch: TODO: determine, if necessary
% (probably needed for new line simplification algorithm)
% not possible in octave
new.ScreenPixelsPerInch.val = 96;
new.ScreenPixelsPerInch.ignore = strcmpi(getEnvironment,'octave');
% MATLAB's factory values differ from their default values of a clean
% MATLAB installation (observed on R2014a, Linux)
new.defaultAxesColor.val = [1 1 1];
new.defaultAxesColor.ignore = false;
new.defaultLineColor.val = [0 0 0];
new.defaultLineColor.ignore = false;
new.defaultTextColor.val = [0 0 0];
new.defaultTextColor.ignore = false;
new.defaultAxesXColor.val = [0 0 0];
new.defaultAxesXColor.ignore = false;
new.defaultAxesYColor.val = [0 0 0];
new.defaultAxesYColor.ignore = false;
new.defaultAxesZColor.val = [0 0 0];
new.defaultAxesZColor.ignore = false;
new.defaultFigureColor.val = [0.8 0.8 0.8];
new.defaultFigureColor.ignore = false;
new.defaultPatchEdgeColor.val = [0 0 0];
new.defaultPatchEdgeColor.ignore = false;
new.defaultPatchFaceColor.val = [0 0 0];
new.defaultPatchFaceColor.ignore = false;
new.defaultFigurePaperType.val = 'A4';
new.defaultFigurePaperType.ignore = false;
new.defaultFigurePaperSize.val = [20.9840 29.6774];
new.defaultFigurePaperSize.ignore = false;
new.defaultFigurePaperUnits.val = 'centimeters';
new.defaultFigurePaperUnits.ignore = false;
%--- Extract relevant properties and set desired state
f = fieldnames(new); % fields of new state
for i = 1:length(f)
% ignore property on specified environments
if ~new.(f{i}).ignore
val = swapPropertyState(0, f{i}, new.(f{i}).val);
% store original value only, if not set by user's defaults
if ~isfield(orig,f{i})
orig.(f{i}).val = val;
end
end
end
end
% =========================================================================
function old = swapPropertyState(h, property, new)
% read current property of graphical object
% set new value, if not empty
if nargin < 3, new = []; end
old = get(h, property);
if ~isempty(new)
set(h, property, new);
end
end

View File

@@ -0,0 +1,19 @@
function hashTable = loadHashTable(suite)
% loads a reference hash table from disk
hashTable.suite = suite;
hashTable.contents = struct();
filename = hashTableName(suite);
if exist(filename, 'file')
fid = fopen(filename, 'r');
finally_fclose_fid = onCleanup(@() fclose(fid));
data = textscan(fid, '%s : %s');
if ~isempty(data) && ~all(cellfun(@isempty, data))
functions = cellfun(@strtrim, data{1},'UniformOutput', false);
hashes = cellfun(@strtrim, data{2},'UniformOutput', false);
for iFunc = 1:numel(functions)
hashTable.contents.(functions{iFunc}) = hashes{iFunc};
end
end
end
end

View File

@@ -0,0 +1,30 @@
function rootpath = m2troot(varargin)
% M2TROOT produces paths inside the matlab2tikz repository
%
% Usage:
% There are two ways to call this function, the base syntax is:
%
% * rootpath = m2troot()
%
% where |rootpath| points towards the root of the repository.
%
% The other syntax:
%
% * path = m2troot(...)
%
% is equivalent to |fullfile(m2troot, ...)| and as such allows to
% easily produce a path to any file within the repository.
m2t = which('matlab2tikz');
if isempty(m2t)
error('M2TRoot:NotFound', 'Matlab2tikz was not found on the PATH!')
end
[srcpath] = fileparts(m2t); % this should be $(m2troot)/src
[rootpath, srcdir] = fileparts(srcpath); % this should be $(m2troot)
assert(strcmpi(srcdir,'src'));
if nargin >= 1
rootpath = fullfile(rootpath, varargin{:});
end
end

View File

@@ -0,0 +1,24 @@
function [ newstr ] = m2tstrjoin( cellstr, delimiter )
%M2TSTRJOIN This function joins a cellstr with a separator
%
% This is an alternative implementation for MATLAB's `strjoin`, since that
% one is not available before R2013a.
%
% See also: strjoin
%TODO: Unify the private `m2tstrjoin` functions
%FIXME: differs from src/private/m2tstrjoin in functionality !!!
nElem = numel(cellstr);
if nElem == 0
newstr = '';
return % m2tstrjoin({}, ...) -> ''
end
newstr = cell(2,nElem);
newstr(1,:) = reshape(cellstr, 1, nElem);
newstr(2,1:nElem-1) = {delimiter}; % put delimiters in-between the elements
newstr(2, end) = {''}; % for Octave 4 compatibility
newstr = [newstr{:}];
end

View File

@@ -0,0 +1,11 @@
function restoreGlobalState(orig)
% Restore original properties of global state.
% See #542 and #552
fprintf('Restore global state...\n');
% Restore relevant properties
state_fields = fieldnames(orig);
for i = 1:length(state_fields)
set(0, state_fields{i}, orig.(state_fields{i}).val);
end
end

View File

@@ -0,0 +1,10 @@
function [passedTests, failedTests, skippedTests] = splitPassFailSkippedTests(status)
% splits tests between passed, failed and skippedtests
skipped = cellfun(@(s) s.skip, status);
status_notSkipped = status(~skipped);
failed = hasTestFailed(status_notSkipped);
passedTests = status_notSkipped(~failed);
failedTests = status_notSkipped(failed);
skippedTests = status(skipped);
end

View File

@@ -0,0 +1,7 @@
function [reliableTests, unreliableTests] = splitUnreliableTests(status)
% splits tests between reliable and unreliable tests
knownToFail = cellfun(@(s)s.unreliable, status);
unreliableTests = status( knownToFail);
reliableTests = status(~knownToFail);
end

View File

@@ -0,0 +1,146 @@
function [status, parameters] = testMatlab2tikz(varargin)
%TESTMATLAB2TIKZ unit test driver for matlab2tikz
%
% This function should NOT be called directly by the user (or even developer).
% If you are a developer, please use some of the following functions instead:
% * `testHeadless`
% * `testGraphical`
%
% The following arguments are supported, also for the functions above.
%
% TESTMATLAB2TIKZ('testFunctionIndices', INDICES, ...) or
% TESTMATLAB2TIKZ(INDICES, ...) runs the test only for the specified
% indices. When empty, all tests are run. (Default: []).
%
% TESTMATLAB2TIKZ('extraOptions', {'name',value, ...}, ...)
% passes the cell array of options to MATLAB2TIKZ. Default: {}
%
% TESTMATLAB2TIKZ('figureVisible', LOGICAL, ...)
% plots the figure visibly during the test process. Default: false
%
% TESTMATLAB2TIKZ('testsuite', FUNCTION_HANDLE, ...)
% Determines which test suite is to be run. Default: @ACID
% A test suite is a function that takes a single integer argument, which:
% when 0: returns a cell array containing the N function handles to the tests
% when >=1 and <=N: runs the appropriate test function
% when >N: throws an error
%
% TESTMATLAB2TIKZ('output', DIRECTORY, ...)
% Sets the output directory where the output files are places.
% The default directory is $M2TROOT/test/output/current
%
% See also matlab2tikz, ACID
% In which environment are we?
env = getEnvironment();
% -----------------------------------------------------------------------
ipp = m2tInputParser;
ipp = ipp.addOptional(ipp, 'testFunctionIndices', [], @isfloat);
ipp = ipp.addParamValue(ipp, 'extraOptions', {}, @iscell);
ipp = ipp.addParamValue(ipp, 'figureVisible', false, @islogical);
ipp = ipp.addParamValue(ipp, 'actionsToExecute', @(varargin) varargin{1}, @isFunction);
ipp = ipp.addParamValue(ipp, 'testsuite', @ACID, @isFunction );
ipp = ipp.addParamValue(ipp, 'output', m2troot('test','output','current'), @ischar);
ipp = ipp.parse(ipp, varargin{:});
ipp = sanitizeInputs(ipp);
parameters = ipp.Results;
% -----------------------------------------------------------------------
if strcmpi(env, 'Octave')
if ~ipp.Results.figureVisible
% Use the gnuplot backend to work around an fltk bug, see
% <http://savannah.gnu.org/bugs/?43429>.
graphics_toolkit gnuplot
end
if ispc
% Prevent three digit exponent on Windows Octave
% See https://github.com/matlab2tikz/matlab2tikz/pull/602
setenv ('PRINTF_EXPONENT_DIGITS', '2')
end
end
% copy output template into output directory
if ~exist(ipp.Results.output,'dir')
mkdir(ipp.Results.output);
end
template = m2troot('test','template');
copyfile(fullfile(template,'*'), ipp.Results.output);
% start overall timing
elapsedTimeOverall = tic;
status = runIndicatedTests(ipp);
% print out overall timing
elapsedTimeOverall = toc(elapsedTimeOverall);
stdout = 1;
fprintf(stdout, 'overall time: %4.2fs\n\n', elapsedTimeOverall);
end
% INPUT VALIDATION =============================================================
function bool = isFunction(f)
bool = isa(f,'function_handle');
end
function ipp = sanitizeInputs(ipp)
% sanitize all input arguments
ipp = sanitizeFunctionIndices(ipp);
ipp = sanitizeFigureVisible(ipp);
end
function ipp = sanitizeFunctionIndices(ipp)
% sanitize the passed function indices to the range of the test suite
% query the number of test functions
testsuite = ipp.Results.testsuite;
n = length(testsuite(0));
if ~isempty(ipp.Results.testFunctionIndices)
indices = ipp.Results.testFunctionIndices;
% kick out the illegal stuff
I = find(indices>=1 & indices<=n);
indices = indices(I); %#ok
else
indices = 1:n;
end
ipp.Results.testFunctionIndices = indices;
end
function ipp = sanitizeFigureVisible(ipp)
% sanitizes the figure visible option from boolean to ON/OFF
if ipp.Results.figureVisible
ipp.Results.figureVisible = 'on';
else
ipp.Results.figureVisible = 'off';
end
end
% TEST RUNNER ==================================================================
function status = runIndicatedTests(ipp)
% run all indicated tests in the test suite
% cell array to accomodate different structure
indices = ipp.Results.testFunctionIndices;
testsuite = ipp.Results.testsuite;
testsuiteName = func2str(testsuite);
stdout = 1;
status = cell(length(indices), 1);
for k = 1:length(indices)
testNumber = indices(k);
fprintf(stdout, 'Executing %s test no. %d...\n', testsuiteName, indices(k));
status{k} = emptyStatus(testsuite, testNumber);
elapsedTime = tic;
status{k} = feval(ipp.Results.actionsToExecute, status{k}, ipp);
elapsedTime = toc(elapsedTime);
status{k}.elapsedTime = elapsedTime;
fprintf(stdout, '%s ', status{k}.function);
if status{k}.skip
fprintf(stdout, 'skipped (%4.2fs).\n\n', elapsedTime);
else
fprintf(stdout, 'done (%4.2fs).\n\n', elapsedTime);
end
end
end