diff --git a/WorkshopProject.prj b/DevOps.prj similarity index 100% rename from WorkshopProject.prj rename to DevOps.prj diff --git a/README.md b/README.md index 7849f93..dfd68bc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![MATLAB](https://github.com/simkaryote/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml/badge.svg)](https://github.com/simkaryote/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml) -[![Tests](https://img.shields.io/badge/Tests-Open_Test_Report-blue)](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/tests/) -[![Coverage](https://img.shields.io/badge/Coverage-Open_Code_Coverage_Report-orange)](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/coverage/) +[![MATLAB](https://github.com/ChezJe/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml/badge.svg)](https://github.com/ChezJe/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml) +[![Tests](https://img.shields.io/badge/Tests-Open_Test_Report-blue)](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/tests/) +[![Coverage](https://img.shields.io/badge/Coverage-Open_Code_Coverage_Report-orange)](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/coverage/) # Generating Tests for Your MATLAB® Code Workshop diff --git a/buildfile.m b/buildfile.m index 820d3a6..20f86c2 100644 --- a/buildfile.m +++ b/buildfile.m @@ -1,22 +1,20 @@ function plan = buildfile - import matlab.buildtool.tasks.* +% Extract tasks from local functions plan = buildplan(localfunctions); -% Set default task -plan.DefaultTasks = "test"; - - % CodeIssues task -plan("check") = CodeIssuesTask(); +plan("check") = CodeIssuesTask(Results=["results/codeissues.sarif"; ... + "results/codeissues.mat"]); % Test task tTask = TestTask("tests", ... SourceFiles = "code", ... IncludeSubfolders = true,... - TestResults = fullfile("results","tests","index.html"), ... - Dependencies = "check"); + TestResults = fullfile("results","tests","index.html"),... + RunOnlyImpactedTests=true); + tTaskWithMatlabTest = tTask.addCodeCoverage( ... fullfile("results","coverage","index.html"), ... MetricLevel = "condition"); % Note: Change MetricLevel to "statement" @@ -26,4 +24,52 @@ % Clean task plan("clean") = CleanTask(); +% Define dependencies +plan("compile").Dependencies = "test"; +plan("test").Dependencies = "generateSimFun"; +plan("generateSimFun").Dependencies = "check"; + +% Define inputs and outputs +proj = currentProject; +plan("generateSimFun").Inputs = fullfile(proj.RootFolder,"code","*.sbproj"); +plan("generateSimFun").Outputs = fullfile(proj.RootFolder,"code","*.mat"); +plan("test").Inputs = fullfile(proj.RootFolder,"code","*"); +plan("compile").Inputs = fullfile(proj.RootFolder,"code",["*.mat","*.mlapp","graystyle.m"]); +plan("compile").Outputs = fullfile(proj.RootFolder,"WebAppArchive"); + +% Set default task +plan.DefaultTasks = "compile"; + + +end + +function generateSimFunTask(~) + % Generate SimFunction and associated MAT file for app to run + generateSimFun(); +end + +function compileTask(~) + % Compile App into Web App + + proj = currentProject; + rootFolder = proj.RootFolder; % Get the root folder of the project + + imgFiles = dir(fullfile(rootFolder,"code","images","*.*")); + imgFiles = string({imgFiles.name}'); + imgFiles = fullfile(rootFolder,"code","images",imgFiles(~matches(imgFiles,[".",".."]))); + codeFiles = dir(fullfile(rootFolder,"code","*.m")); + codeFiles = string({codeFiles.name}'); + codeFiles = fullfile(rootFolder,"code",setdiff(codeFiles,"generateSimFun.m")); + + MATfilename = dir(fullfile(rootFolder,"code","*.mat")); + MATfilename = fullfile(rootFolder,"code",MATfilename.name); + load(MATfilename,"dependenciesSimFun"); + + appDependencies = [MATfilename; dependenciesSimFun; ... + codeFiles; imgFiles]; + appfilename = fullfile(rootFolder,"code","TMDDApp.mlapp"); + + compiler.build.webAppArchive(appfilename,... + AdditionalFiles=appDependencies,OutputDir="WebAppArchive"); + end diff --git a/code/ConcTimecourseView.m b/code/ConcTimecourseView.m new file mode 100644 index 0000000..a341078 --- /dev/null +++ b/code/ConcTimecourseView.m @@ -0,0 +1,75 @@ +classdef ConcTimecourseView < handle + + properties ( Access = private ) + Model + Axes + + ConcColors = [0.30,0.75,0.93;... + 0.86,0.55,0.41;... + 0.91,0.73,0.42]; % colors to plot concentrations + FontName = "Helvetica"; + end + + properties ( SetAccess=private, GetAccess={?tTMDDApp} ) + % line handles + lhDrug + lhReceptor + lhComplex + + end + + properties( Access = private ) + DataListener % listener + end + + methods + function obj = ConcTimecourseView(parent, model) + + arguments + parent + model (1,1) SimulationModel + end + + ax = uiaxes(parent); + graystyle(ax); + xlabel(ax, "Time (hours)", 'FontName',obj.FontName); + ylabel(ax, "Concentrations (nanomole/liter)",'FontName',obj.FontName); + + obj.lhDrug = plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(1,:)); + hold(ax,'on'); + obj.lhReceptor = plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(2,:)); + obj.lhComplex= plot(ax, NaN, NaN, '-','Linewidth',2,'Color',obj.ConcColors(3,:)); + hold(ax,'off'); + lh = legend(ax,{'Drug','Receptor','Complex'},'FontName',obj.FontName); + lh.Box = 'off'; + + % instantiate listener + dataListener = event.listener( model, 'DataChanged', ... + @obj.update ); + + % store listeners + obj.DataListener = dataListener; + + % save objects + obj.Model = model; + obj.Axes = ax; + + end % constructor + + + end % public methods + + methods ( Access = private ) + + function update(obj,~,~) + t = obj.Model.SimDataTable; + + set(obj.lhDrug,'XData',t.Time, 'YData',t.Drug); + set(obj.lhReceptor,'XData',t.Time, 'YData',t.Receptor); + set(obj.lhComplex,'XData',t.Time, 'YData',t.Complex); + + end % update + + end % private method +end % class + diff --git a/code/LampView.m b/code/LampView.m new file mode 100644 index 0000000..c457ec1 --- /dev/null +++ b/code/LampView.m @@ -0,0 +1,70 @@ +classdef LampView < handle + + properties ( Dependent ) + IsOn (1,1) logical + end + + properties + LampColorSucess = [0.47, 0.67, 0.19] % color of lamp if RO between thresholds after day 1 + LampColorFailure = [0.85, 0.33, 0.10] % color of lamp if RO not between thresholds after day 1 + end + + properties ( SetAccess=private, GetAccess={?tTMDDApp} ) + LampObj + end + + properties ( Access=private ) + Model + end + + properties( Access = private ) + DataListener % listener + end + + methods + function obj = LampView(parent,model) + + lampObj = uilamp(parent); + lampObj.Tooltip = compose("Target occupancy does not remain\n between thresholds"); + lampObj.Color = obj.LampColorFailure; + + % instantiate listener + dataListener = event.listener( model, 'DataChanged', ... + @obj.update ); + + % store listeners + obj.DataListener = dataListener; + + obj.LampObj = lampObj; + obj.Model = model; + + end % constructor + + function set.IsOn(obj, value) + % color lamp according to whether or not RO remains between thresholds after day 1 + if value + obj.LampObj.Color = obj.LampColorSucess; + obj.LampObj.Tooltip = compose("Target occupancy remains\n between thresholds"); + else + obj.LampObj.Color = obj.LampColorFailure; + obj.LampObj.Tooltip = compose("Target occupancy does not remain\n between thresholds"); + end + + obj.LampObj.UserData = value; + + end % set.IsOn + + function value = get.IsOn(obj) + value = obj.LampObj.UserData; + end % get.IsOn + + end % public methods + + methods ( Access = private ) + + function update(obj,~,~) + obj.IsOn = obj.Model.ROIsBetweenThresholds; + end % update + + end % private method +end \ No newline at end of file diff --git a/code/NCAView.m b/code/NCAView.m new file mode 100644 index 0000000..9f05d46 --- /dev/null +++ b/code/NCAView.m @@ -0,0 +1,87 @@ +classdef NCAView < handle + + properties ( Access = private ) + Model + NCApanel + GridLayout + + end + + properties ( SetAccess=private, GetAccess={?tTMDDApp} ) + NCAtable + end + + properties ( Access = public ) + FontName (1,1) string = "Helvetica" + NCAoptions % options for NCA calculations + ConcentrationColumnName (1,1) string = "Complex" + end + + properties( Access = private ) + DataListener % listener + end + + methods + function obj = NCAView(parent, model) + + arguments + parent + model (1,1) SimulationModel + end + + ncapanel = uipanel(parent); + ncapanel.Title = "NCA parameters for bound target ('" + ... + obj.ConcentrationColumnName + "')"; + ncapanel.BackgroundColor = [1 1 1]; + ncapanel.FontName = obj.FontName; + ncapanel.BorderType = 'none'; + + % Create GridLayout + gl = uigridlayout(ncapanel); + gl.ColumnWidth = {'1x'}; + gl.RowHeight = {'1x'}; + gl.Padding = [0 0 0 0]; + gl.BackgroundColor = [1 1 1]; + + % Create NCAtable + ncat = uitable(gl); + + % save NCA options + opt = sbioncaoptions; + opt.concentrationColumnName = obj.ConcentrationColumnName; + opt.timeColumnName = 'Time'; + opt.IVDoseColumnName = 'Dose'; + + % instantiate listener + dataListener = event.listener( model, 'DataChanged', ... + @obj.update ); + + % store listeners + obj.DataListener = dataListener; + + % save objects + obj.Model = model; + obj.NCAoptions = opt; + obj.NCApanel = ncapanel; + obj.GridLayout = gl; + obj.NCAtable = ncat; + + end % constructor + + + end % public methods + + methods ( Access = private ) + + function update(obj,~,~) + + % compute NCA parameters and display them in table + ncaParameters = sbionca(obj.Model.SimDataTable, obj.NCAoptions); + obj.NCAtable.ColumnName = ncaParameters.Properties.VariableNames(2:end); + obj.NCAtable.Data = ncaParameters(:,2:end); + + end % update + + end % private method +end % class + diff --git a/code/ROTimecourseView.m b/code/ROTimecourseView.m new file mode 100644 index 0000000..84d9e50 --- /dev/null +++ b/code/ROTimecourseView.m @@ -0,0 +1,77 @@ +classdef ROTimecourseView < handle + + properties ( Access = private ) + Model + Axes + + ThresholdStyle = {'Color','r','Linewidth',2,'LineStyle','--',... + 'FontWeight','bold','LabelVerticalAlignment','middle'}; % style for threshold lines + end + + properties ( GetAccess = {?tTMDDApp} ) + % line handles + lhRO + end + + properties ( Access = public ) + ConcColors = [0.30,0.75,0.93;... + 0.86,0.55,0.41;... + 0.91,0.73,0.42]; % colors to plot concentrations + ROColors = [0.30,0.75,0.93]; + FontName = "Helvetica"; + end + + properties( Access = private ) + DataListener % listener + end + + methods + function obj = ROTimecourseView(parent, model) + + arguments + parent + model (1,1) SimulationModel + end + + ax = uiaxes(parent); + graystyle(ax); + xlabel(ax, "Time (hours)", 'FontName',obj.FontName); + ylabel(ax, "RO (%)",'FontName',obj.FontName); + + obj.lhRO = plot(ax, NaN, NaN, 'Color', obj.ROColors,'Linewidth',2); + yline(ax,model.ThresholdValues(1), '--','efficacy','FontName',obj.FontName,obj.ThresholdStyle{:}); + yline(ax,model.ThresholdValues(2), '--','safety','FontName',obj.FontName,obj.ThresholdStyle{:}); + + + % set limits + xlim(ax,'auto'); + ylim(ax,[-5, 105]); + + % instantiate listener + dataListener = event.listener( model, 'DataChanged', ... + @obj.update ); + + % store listeners + obj.DataListener = dataListener; + + % save objects + obj.Model = model; + obj.Axes = ax; + + end % constructor + + + end % public methods + + methods ( Access = private ) + + function update(obj,~,~) + t = obj.Model.SimDataTable; + + set(obj.lhRO,'XData',t.Time, 'YData',100*t.RO); + + end % update + + end % private method +end % class + diff --git a/code/SimulationModel.m b/code/SimulationModel.m new file mode 100644 index 0000000..d4b4811 --- /dev/null +++ b/code/SimulationModel.m @@ -0,0 +1,93 @@ +classdef SimulationModel < handle +% Class to simulate the TMDD model + + properties ( SetAccess = private ) + DoseTable % daily dose to apply to simulate + SimFun % exported SimFunction + + SimData + SimDataTable + + ThresholdValues = [20, 80] % threshold values + + end + + properties + % original values for resetting + Amount0 (1,1) double + Duration0 (1,1) double + Kon0 (1,1) double + Kel0 (1,1) double + Kdeg0 (1,1) double + Interval0 (1,1) double + ROIsBetweenThresholds (1,1) logical + end + + events ( NotifyAccess = private ) + DataChanged + end + + methods + + function obj = SimulationModel() + % load Simfunction and dosing information + load('simFunction_Dose.mat', 'simFun', 'doseTable'); + obj.SimFun = simFun; + obj.DoseTable = doseTable; + + + % save original values to allow for resetting + obj.Kel0 = obj.SimFun.Parameters.Value(1); + obj.Kon0 = obj.SimFun.Parameters.Value(2); + obj.Kdeg0 = obj.SimFun.Parameters.Value(3); + obj.Duration0 = 119; + obj.Interval0 = obj.DoseTable.Interval; + obj.Amount0 = obj.DoseTable.Amount; + + end % constructor + + end + + methods + + function simulate(obj, parameters) + + arguments + obj + parameters (1,:) double + end + + cellpar = num2cell(parameters); + [kel, kon, kdeg,stopTime, amount, interval] = deal(cellpar{:}); + obj.DoseTable.Amount = amount; + obj.DoseTable.Interval = interval; + + sd = obj.SimFun([kel, kon, kdeg], stopTime, obj.DoseTable); + t = array2table([sd.Time, sd.Data], 'VariableNames',[{'Time'}; sd.DataNames]); + t.Properties.VariableUnits = [{'hours'}; cellfun(@(x) x.Units, sd.DataInfo, 'UniformOutput', false)]; + + % add dosing information to table to compute NCA parameters + t.Dose = NaN(height(t),1); + dosingTimes = interval*(0:stopTime/interval); + t.Dose(ismember(t.Time, dosingTimes)) = amount; + idxNotIncreasing = diff(t.Time)<=0; % remove duplicates + t(idxNotIncreasing,:) = []; + + % logical value to check whether or not RO remains between thresholds after day 1 + aboveThreshold1 = all(t.RO(t.Time >= 24) >= obj.ThresholdValues(1)/100); + belowThreshold2 = all(t.RO(t.Time >= 24) <= obj.ThresholdValues(2)/100); + obj.ROIsBetweenThresholds = aboveThreshold1 && belowThreshold2; + + obj.SimData = sd; + obj.SimDataTable = t; + + notify( obj, 'DataChanged' ); + + end % simulate + + + end % public methods + + +end % classdef + diff --git a/code/TMDD.sbproj b/code/TMDD.sbproj new file mode 100644 index 0000000..be0de33 Binary files /dev/null and b/code/TMDD.sbproj differ diff --git a/code/TMDDApp.mlapp b/code/TMDDApp.mlapp new file mode 100644 index 0000000..97c89dc Binary files /dev/null and b/code/TMDDApp.mlapp differ diff --git a/code/generateSimFun.m b/code/generateSimFun.m new file mode 100644 index 0000000..6dbc5b8 --- /dev/null +++ b/code/generateSimFun.m @@ -0,0 +1,44 @@ +function MATfilename = generateSimFun(MATfilename) + +arguments + MATfilename = "simFunction_Dose.mat" +end + +% if only a file name without folder name is provided, make sure the MAT +% file is saved in the same directory as generateSimFun.m +if ~contains(MATfilename,filesep) + fullpath = mfilename('fullpath'); + folder = fileparts(fullpath); + MATfilename = fullfile(folder,MATfilename); +end + +% Load the SimBiology project into the workspace +s = sbioloadproject("TMDD.sbproj",'m1'); +modelObj = s.m1; +doseObj = modelObj.getdose('Daily Dose'); +basevariantObj = modelObj.getvariant('Estimated values'); + +% Use hours for dose timing and convert any day-based interval to hours +oldTimeUnit = doseObj.TimeUnits; +doseObj.TimeUnits = 'hour'; +doseObj.Interval = sbiounitcalculator(oldTimeUnit, ... + doseObj.TimeUnits, doseObj.Interval); + +% Increase the number of repeat doses for long simulations +doseObj.RepeatCount = 200; + +% Save dose table for simulation +doseTable = doseObj.getTable(); + +% Create a simulation function +simFun = modelObj.createSimFunction({'kel','kon','kdeg'}, ... + {'Drug','Receptor','Complex','RO'}, doseObj.TargetName, basevariantObj); + +% Compile the simulation function for faster execution +simFun.accelerate(); +dependenciesSimFun = simFun.DependentFiles'; + +% Create MAT file +save(MATfilename,"simFun","doseTable","dependenciesSimFun"); + +end diff --git a/code/graystyle.m b/code/graystyle.m new file mode 100644 index 0000000..0dfce90 --- /dev/null +++ b/code/graystyle.m @@ -0,0 +1,50 @@ +function graystyle(axh) + +% Set figure background to white +fh = axh.Parent; +if isprop(fh,'Color') + fh.Color = 'w'; +elseif isprop(fh,'BackgroundColor') + fh.BackgroundColor = 'w'; +end + + +% Set axes background and edges to gray +axh.Color = ones(1,3)*0.9; +axh.XColor = axh.Color; +axh.YColor = axh.Color; +axh.ZColor = axh.Color; + +% Set grid to white +axh.GridColor = 'white'; +axh.GridAlpha = 1; %0.4; +axh.Layer = 'bottom'; +grid(axh,'on'); + +% Set ticks and box +axh.TickDir = 'out'; +axh.TickLength = [0.005 0.012]; +axh.Box = 'off'; + +% Set TickLabels color to gray +axh.XAxis.TickLabelFormat = '\\color\[rgb\]\{0.5,0.5,0.5\} %g'; +axh.YAxis.TickLabelFormat = axh.XAxis.TickLabelFormat; +axh.ZAxis.TickLabelFormat = axh.XAxis.TickLabelFormat; + +% Set label colors to same colors as TickLabels +axh.XLabel.Color = ones(1,3)*0.4; +axh.YLabel.Color = axh.XLabel.Color; +axh.ZLabel.Color = axh.XLabel.Color; + +% Set legend +lh = legend(axh,'hide'); +lh.EdgeColor = [1 1 1]; + + +% Set Linewidth for children +if ~isempty(axh.Children) + set(axh.Children, 'LineWidth',1.5) +end + +end + \ No newline at end of file diff --git a/code/images/Run_24.png b/code/images/Run_24.png new file mode 100644 index 0000000..550f4b5 Binary files /dev/null and b/code/images/Run_24.png differ diff --git a/code/images/diagram.png b/code/images/diagram.png new file mode 100644 index 0000000..3daaa68 Binary files /dev/null and b/code/images/diagram.png differ diff --git a/code/images/diagram.svg b/code/images/diagram.svg new file mode 100644 index 0000000..eb2836d --- /dev/null +++ b/code/images/diagram.svg @@ -0,0 +1,265 @@ + + +PlasmaDrugDrug Elim (kel)Receptor Binding (kon/koff)ReceptorComplexComplex Elim (km)Receptor Synthesis (ksyn)Receptor Elim (kdeg)Receptor*kdeg*PlasmaComplex/(Receptor+Complex)RO diff --git a/code/isLeapYear.m b/code/isLeapYear.m deleted file mode 100644 index 64c0a93..0000000 --- a/code/isLeapYear.m +++ /dev/null @@ -1,32 +0,0 @@ -function isLeap = isLeapYear(year) -%ISLEAPYEAR Determine if a year is a leap year -% -% isLeap = isLeapYear(year) returns true if the year is a leap year -% - Leap years are divisible by 400, or divisible by 4 and not 100 -% -% Example: -% isLeapYear(2000) % returns true -% isLeapYear(2024) % returns true -% isLeapYear(2025) % returns false - -arguments - year (1,1) {mustBeInteger, mustBePositive} -end - -% Set up logical comparisons for clarity -isDivBy400 = mod(year,400) == 0; -isDivBy100 = mod(year,100) == 0; -isDivBy4 = mod(year, 4) == 0; - -% Check for leap year -if isDivBy400 - isLeap = true; -elseif isDivBy4 - isLeap = true; -elseif isDivBy100 - isLeap = false; -else - isLeap = false; -end - -end diff --git a/code/rockPaperScissors.m b/code/rockPaperScissors.m deleted file mode 100644 index 8e8f89a..0000000 --- a/code/rockPaperScissors.m +++ /dev/null @@ -1,37 +0,0 @@ -function result = rockPaperScissors(p1, p2) -% rockPaperScissors Determine the winner of a Rock-Paper-Scissors game -% -% result = rockPaperScissors(p1, p2) returns a string indicating the outcome: -% - "Tie" if both players choose the same -% - "Player 1 wins" if player 1 beats player 2 -% - "Player 2 wins" if player 2 beats player 1 -% - Error if either input is invalid -% -% Valid inputs: "rock", "paper", "scissors" (case-insensitive) -% -% Example: -% rockPaperScissors("rock", "scissors") % returns "Player 1 wins" -% rockPaperScissors("paper", "rock") % returns "Player 1 wins" -% rockPaperScissors("scissors", "scissors") % returns "Tie" - -arguments - p1 (1,1) string {mustBeMember(p1,["rock","paper","scissors"])} - p2 (1,1) string {mustBeMember(p2,["rock","paper","scissors"])} -end - -rockVsScissors = p1 == "rock" && p2 == "scissors"; -scissorsVsPaper = p1 == "scissors" && p2 == "paper"; -paperVsRock = p1 == "paper" && p2 == "rock"; - -% Compare hands -if p1 == p2 - result = "Tie"; - -elseif rockVsScissors || scissorsVsPaper || paperVsRock - result = "Player 1 wins"; - -else - result = "Player 2 wins"; -end - -end diff --git a/code/simFunction_Dose.mat b/code/simFunction_Dose.mat new file mode 100644 index 0000000..c9b533b Binary files /dev/null and b/code/simFunction_Dose.mat differ diff --git a/code/simpleSort.m b/code/simpleSort.m deleted file mode 100644 index 5f1a423..0000000 --- a/code/simpleSort.m +++ /dev/null @@ -1,34 +0,0 @@ -function sortedArray = simpleSort(inputVector) -%SIMPLESORT Uses a Bubble Sort algorithm to sort an array of numbers in -% ascending order -% -% sortedArray = simpleSort(array) returns a new array with the same -% elements as the input array, sorted in ascending order -% -% Example: -% simpleSort([3, 1, 4, 1, 5]) % returns [1 1 3 4 5] -% -% Input must be a numeric vector. - -arguments - inputVector {mustBeNumeric,mustBeVector(inputVector,"allow-all-empties")} -end - -% Copy the array to avoid modifying the input -sortedArray = inputVector; - -n = length(sortedArray); - -% Bubble Sort algorithm -for ii = 1:n-1 - for jj = 1:n-ii - if sortedArray(jj) > sortedArray(jj+1) - % Swap elements - temp = sortedArray(jj); - sortedArray(jj) = sortedArray(jj+1); - sortedArray(jj+1) = temp; - end - end -end - -end diff --git a/images/image_0.svg b/images/image_0.svg deleted file mode 100644 index f2c8c7d..0000000 --- a/images/image_0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_1.svg b/images/image_1.svg deleted file mode 100644 index 569a860..0000000 --- a/images/image_1.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_10.svg b/images/image_10.svg deleted file mode 100644 index 4c4fe59..0000000 --- a/images/image_10.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_11.svg b/images/image_11.svg deleted file mode 100644 index 2114a01..0000000 --- a/images/image_11.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_12.png b/images/image_12.png deleted file mode 100644 index dba759c..0000000 Binary files a/images/image_12.png and /dev/null differ diff --git a/images/image_13.png b/images/image_13.png deleted file mode 100644 index 440f297..0000000 Binary files a/images/image_13.png and /dev/null differ diff --git a/images/image_14.png b/images/image_14.png deleted file mode 100644 index 7383aa7..0000000 Binary files a/images/image_14.png and /dev/null differ diff --git a/images/image_15.svg b/images/image_15.svg deleted file mode 100644 index 1f26e4b..0000000 --- a/images/image_15.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_16.svg b/images/image_16.svg deleted file mode 100644 index cdbba83..0000000 --- a/images/image_16.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_17.svg b/images/image_17.svg deleted file mode 100644 index 3c35be2..0000000 --- a/images/image_17.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_18.svg b/images/image_18.svg deleted file mode 100644 index 4ac79b5..0000000 --- a/images/image_18.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_19.svg b/images/image_19.svg deleted file mode 100644 index 5611eb9..0000000 --- a/images/image_19.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_2.svg b/images/image_2.svg deleted file mode 100644 index 33f45f5..0000000 --- a/images/image_2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_20.svg b/images/image_20.svg deleted file mode 100644 index c51f5c9..0000000 --- a/images/image_20.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_21.svg b/images/image_21.svg deleted file mode 100644 index defb2cb..0000000 --- a/images/image_21.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_22.png b/images/image_22.png deleted file mode 100644 index 44e7516..0000000 Binary files a/images/image_22.png and /dev/null differ diff --git a/images/image_23.png b/images/image_23.png deleted file mode 100644 index e2065da..0000000 Binary files a/images/image_23.png and /dev/null differ diff --git a/images/image_24.svg b/images/image_24.svg deleted file mode 100644 index 613e9cc..0000000 --- a/images/image_24.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_25.png b/images/image_25.png deleted file mode 100644 index 4cc50d0..0000000 Binary files a/images/image_25.png and /dev/null differ diff --git a/images/image_26.svg b/images/image_26.svg deleted file mode 100644 index 38041b7..0000000 --- a/images/image_26.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_27.png b/images/image_27.png deleted file mode 100644 index 44e7516..0000000 Binary files a/images/image_27.png and /dev/null differ diff --git a/images/image_28.png b/images/image_28.png deleted file mode 100644 index 92c7995..0000000 Binary files a/images/image_28.png and /dev/null differ diff --git a/images/image_29.svg b/images/image_29.svg deleted file mode 100644 index 52281b0..0000000 --- a/images/image_29.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_3.svg b/images/image_3.svg deleted file mode 100644 index e02d21c..0000000 --- a/images/image_3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_30.svg b/images/image_30.svg deleted file mode 100644 index 28ef773..0000000 --- a/images/image_30.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_31.svg b/images/image_31.svg deleted file mode 100644 index 90b6eea..0000000 --- a/images/image_31.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_32.svg b/images/image_32.svg deleted file mode 100644 index 188b0b2..0000000 --- a/images/image_32.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_33.svg b/images/image_33.svg deleted file mode 100644 index 21f7656..0000000 --- a/images/image_33.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_34.svg b/images/image_34.svg deleted file mode 100644 index a19b3eb..0000000 --- a/images/image_34.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_35.svg b/images/image_35.svg deleted file mode 100644 index bbeeb48..0000000 --- a/images/image_35.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_36.svg b/images/image_36.svg deleted file mode 100644 index aac8682..0000000 --- a/images/image_36.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_37.svg b/images/image_37.svg deleted file mode 100644 index fb54d1e..0000000 --- a/images/image_37.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_38.svg b/images/image_38.svg deleted file mode 100644 index cbfa599..0000000 --- a/images/image_38.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_39.svg b/images/image_39.svg deleted file mode 100644 index 708177f..0000000 --- a/images/image_39.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_4.svg b/images/image_4.svg deleted file mode 100644 index d6fd4b7..0000000 --- a/images/image_4.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_40.svg b/images/image_40.svg deleted file mode 100644 index 5c33cdc..0000000 --- a/images/image_40.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_41.svg b/images/image_41.svg deleted file mode 100644 index 3a2bb18..0000000 --- a/images/image_41.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_42.svg b/images/image_42.svg deleted file mode 100644 index 8773a4a..0000000 --- a/images/image_42.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_43.svg b/images/image_43.svg deleted file mode 100644 index 7fa1901..0000000 --- a/images/image_43.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_44.svg b/images/image_44.svg deleted file mode 100644 index ab2e9a7..0000000 --- a/images/image_44.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_45.svg b/images/image_45.svg deleted file mode 100644 index c70beb8..0000000 --- a/images/image_45.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_46.svg b/images/image_46.svg deleted file mode 100644 index 2ac3b8d..0000000 --- a/images/image_46.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_47.svg b/images/image_47.svg deleted file mode 100644 index 7016ecf..0000000 --- a/images/image_47.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_48.svg b/images/image_48.svg deleted file mode 100644 index 6886bc7..0000000 --- a/images/image_48.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_49.svg b/images/image_49.svg deleted file mode 100644 index 2465da7..0000000 --- a/images/image_49.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_5.png b/images/image_5.png deleted file mode 100644 index 40abed4..0000000 Binary files a/images/image_5.png and /dev/null differ diff --git a/images/image_50.svg b/images/image_50.svg deleted file mode 100644 index a016667..0000000 --- a/images/image_50.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_51.svg b/images/image_51.svg deleted file mode 100644 index 0364e0b..0000000 --- a/images/image_51.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_52.svg b/images/image_52.svg deleted file mode 100644 index 115c375..0000000 --- a/images/image_52.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_53.png b/images/image_53.png deleted file mode 100644 index f63df4e..0000000 Binary files a/images/image_53.png and /dev/null differ diff --git a/images/image_54.svg b/images/image_54.svg deleted file mode 100644 index 12eadbf..0000000 --- a/images/image_54.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_55.svg b/images/image_55.svg deleted file mode 100644 index 8c46c0a..0000000 --- a/images/image_55.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_56.svg b/images/image_56.svg deleted file mode 100644 index 1609744..0000000 --- a/images/image_56.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_57.svg b/images/image_57.svg deleted file mode 100644 index abf207f..0000000 --- a/images/image_57.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_58.svg b/images/image_58.svg deleted file mode 100644 index d69d9a8..0000000 --- a/images/image_58.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_59.png b/images/image_59.png deleted file mode 100644 index 44e7516..0000000 Binary files a/images/image_59.png and /dev/null differ diff --git a/images/image_6.png b/images/image_6.png deleted file mode 100644 index 572d861..0000000 Binary files a/images/image_6.png and /dev/null differ diff --git a/images/image_60.svg b/images/image_60.svg deleted file mode 100644 index 0c3f339..0000000 --- a/images/image_60.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_61.svg b/images/image_61.svg deleted file mode 100644 index 9093193..0000000 --- a/images/image_61.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_62.png b/images/image_62.png deleted file mode 100644 index d8adb7a..0000000 Binary files a/images/image_62.png and /dev/null differ diff --git a/images/image_63.svg b/images/image_63.svg deleted file mode 100644 index 7861e45..0000000 --- a/images/image_63.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_64.png b/images/image_64.png deleted file mode 100644 index dc4106b..0000000 Binary files a/images/image_64.png and /dev/null differ diff --git a/images/image_65.png b/images/image_65.png deleted file mode 100644 index de9b499..0000000 Binary files a/images/image_65.png and /dev/null differ diff --git a/images/image_66.png b/images/image_66.png deleted file mode 100644 index a4ee7a4..0000000 Binary files a/images/image_66.png and /dev/null differ diff --git a/images/image_67.png b/images/image_67.png deleted file mode 100644 index 5c8a2c8..0000000 Binary files a/images/image_67.png and /dev/null differ diff --git a/images/image_68.png b/images/image_68.png deleted file mode 100644 index cee79fc..0000000 Binary files a/images/image_68.png and /dev/null differ diff --git a/images/image_69.png b/images/image_69.png deleted file mode 100644 index f6fe9b7..0000000 Binary files a/images/image_69.png and /dev/null differ diff --git a/images/image_7.png b/images/image_7.png deleted file mode 100644 index 6d965c0..0000000 Binary files a/images/image_7.png and /dev/null differ diff --git a/images/image_70.svg b/images/image_70.svg deleted file mode 100644 index d2c4005..0000000 --- a/images/image_70.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_71.svg b/images/image_71.svg deleted file mode 100644 index 836d620..0000000 --- a/images/image_71.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_72.png b/images/image_72.png deleted file mode 100644 index 2c82927..0000000 Binary files a/images/image_72.png and /dev/null differ diff --git a/images/image_73.png b/images/image_73.png deleted file mode 100644 index 58c8395..0000000 Binary files a/images/image_73.png and /dev/null differ diff --git a/images/image_74.png b/images/image_74.png deleted file mode 100644 index 799dd18..0000000 Binary files a/images/image_74.png and /dev/null differ diff --git a/images/image_75.png b/images/image_75.png deleted file mode 100644 index 3d1173a..0000000 Binary files a/images/image_75.png and /dev/null differ diff --git a/images/image_76.svg b/images/image_76.svg deleted file mode 100644 index b0154a9..0000000 --- a/images/image_76.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_77.svg b/images/image_77.svg deleted file mode 100644 index 2132119..0000000 --- a/images/image_77.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_78.svg b/images/image_78.svg deleted file mode 100644 index df1a681..0000000 --- a/images/image_78.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_79.png b/images/image_79.png deleted file mode 100644 index acdd1d7..0000000 Binary files a/images/image_79.png and /dev/null differ diff --git a/images/image_8.png b/images/image_8.png deleted file mode 100644 index 520f0f6..0000000 Binary files a/images/image_8.png and /dev/null differ diff --git a/images/image_80.svg b/images/image_80.svg deleted file mode 100644 index e990781..0000000 --- a/images/image_80.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_81.svg b/images/image_81.svg deleted file mode 100644 index d6fd4b7..0000000 --- a/images/image_81.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_82.svg b/images/image_82.svg deleted file mode 100644 index ba9a930..0000000 --- a/images/image_82.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_83.svg b/images/image_83.svg deleted file mode 100644 index 982ce9f..0000000 --- a/images/image_83.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_84.svg b/images/image_84.svg deleted file mode 100644 index db9a1fe..0000000 --- a/images/image_84.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_85.svg b/images/image_85.svg deleted file mode 100644 index f62a975..0000000 --- a/images/image_85.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_86.svg b/images/image_86.svg deleted file mode 100644 index 733ed5c..0000000 --- a/images/image_86.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_87.svg b/images/image_87.svg deleted file mode 100644 index 653e580..0000000 --- a/images/image_87.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_88.svg b/images/image_88.svg deleted file mode 100644 index 03fe0f9..0000000 --- a/images/image_88.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_89.svg b/images/image_89.svg deleted file mode 100644 index b983169..0000000 --- a/images/image_89.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_9.png b/images/image_9.png deleted file mode 100644 index f1494dd..0000000 Binary files a/images/image_9.png and /dev/null differ diff --git a/images/image_90.svg b/images/image_90.svg deleted file mode 100644 index 031784b..0000000 --- a/images/image_90.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/image_91.svg b/images/image_91.svg deleted file mode 100644 index c27f510..0000000 --- a/images/image_91.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/project/Project.xml b/resources/project/Project.xml index e93ed0a..e7171c4 100644 --- a/resources/project/Project.xml +++ b/resources/project/Project.xml @@ -26,166 +26,148 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - + - + - - - - - - - + - - + - - - - - + + + + + + + - - + + - + - + + + + + + + + + + + + + + + + + + + - - - - + - + + + + + + + + + + + + + + + + + + + + + - + - - - - - + + - + - - + + + + + diff --git a/tests/tTMDDApp.m b/tests/tTMDDApp.m new file mode 100644 index 0000000..1957107 --- /dev/null +++ b/tests/tTMDDApp.m @@ -0,0 +1,121 @@ +classdef tTMDDApp < matlab.uitest.TestCase + properties + App + end + + methods (TestMethodSetup) + function launchApp(testCase) + testCase.App = TMDDApp; + testCase.addTeardown(@delete,testCase.App) + end + end + + methods (Test) + + function testStartup(testCase) + + % Check plot update + testCase.verifyNotEmpty(testCase.App.ROViewObj.lhRO.XData, "x values for RO are empty"); + testCase.verifyNotEmpty(testCase.App.ROViewObj.lhRO.YData, "y values for RO are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex are empty"); + testCase.verifyNotEmpty(testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex are empty"); + + % Check NCA table + testCase.verifyNotEmpty(testCase.App.NCAViewObj.NCAtable.Data,"NCA table is empty"); + + end % testStartup + + + function testChangeDosingAmountAutomaticUpdate(testCase) + + % Deactivate automatic plot update + testCase.App.AutomaticupdateCheckBox.Value = false; + + % Simulate for drug=100 + testCase.App.DosingAmountField.Value = 100; + testCase.App.updateApp(); + + oldlhRO_XData = testCase.App.ROViewObj.lhRO.XData; + oldlhRO_YData = testCase.App.ROViewObj.lhRO.YData; + oldlhDrug_XData = testCase.App.ConcViewObj.lhDrug.XData; + oldlhDrug_YData = testCase.App.ConcViewObj.lhDrug.YData; + oldlhReceptor_XData = testCase.App.ConcViewObj.lhReceptor.XData; + oldlhReceptor_YData = testCase.App.ConcViewObj.lhReceptor.YData; + oldlhComplex_XData = testCase.App.ConcViewObj.lhComplex.XData; + oldlhComplex_YData = testCase.App.ConcViewObj.lhComplex.YData; + + % Activate automatic plot update + testCase.App.AutomaticupdateCheckBox.Value = true; + + % Drag slider + testCase.drag(testCase.App.DosingAmountSlider,100,200); + + % Check plot update + testCase.verifyNotEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated"); + testCase.verifyNotEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated"); + testCase.verifyNotEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated"); + testCase.verifyNotEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated"); + testCase.verifyNotEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated"); + testCase.verifyNotEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated"); + testCase.verifyNotEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated"); + testCase.verifyNotEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated"); + + % Check that lamp is set to false + testCase.verifyFalse(testCase.App.LampViewObj.IsOn); + + end % testChangeDosingAmountAutomaticUpdate + + function testChangeDosingAmountManualUpdate(testCase) + + % Deactivate automatic plot update + testCase.App.AutomaticupdateCheckBox.Value = false; + + oldlhRO_XData = testCase.App.ROViewObj.lhRO.XData; + oldlhRO_YData = testCase.App.ROViewObj.lhRO.YData; + oldlhDrug_XData = testCase.App.ConcViewObj.lhDrug.XData; + oldlhDrug_YData = testCase.App.ConcViewObj.lhDrug.YData; + oldlhReceptor_XData = testCase.App.ConcViewObj.lhReceptor.XData; + oldlhReceptor_YData = testCase.App.ConcViewObj.lhReceptor.YData; + oldlhComplex_XData = testCase.App.ConcViewObj.lhComplex.XData; + oldlhComplex_YData = testCase.App.ConcViewObj.lhComplex.YData; + + % Drag slider + testCase.drag(testCase.App.DosingAmountSlider,100,200); + + % Check plot update + testCase.verifyEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated"); + testCase.verifyEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated"); + testCase.verifyEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated"); + testCase.verifyEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated"); + testCase.verifyEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated"); + testCase.verifyEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated"); + testCase.verifyEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated"); + testCase.verifyEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated"); + + % Check that lamp is set to false + testCase.verifyTrue(testCase.App.LampViewObj.IsOn); + + % Update app to run simulation manually + testCase.App.updateApp(); + + % Check plot update + testCase.verifyNotEqual(oldlhRO_XData, testCase.App.ROViewObj.lhRO.XData, "x values for RO not updated"); + testCase.verifyNotEqual(oldlhRO_YData, testCase.App.ROViewObj.lhRO.YData, "y values for RO not updated"); + testCase.verifyNotEqual(oldlhDrug_XData, testCase.App.ConcViewObj.lhDrug.XData, "x values for Drug not updated"); + testCase.verifyNotEqual(oldlhDrug_YData, testCase.App.ConcViewObj.lhDrug.YData, "y values for Drug not updated"); + testCase.verifyNotEqual(oldlhReceptor_XData, testCase.App.ConcViewObj.lhReceptor.XData, "x values for Receptor not updated"); + testCase.verifyNotEqual(oldlhReceptor_YData, testCase.App.ConcViewObj.lhReceptor.YData, "y values for Receptor not updated"); + testCase.verifyNotEqual(oldlhComplex_XData, testCase.App.ConcViewObj.lhComplex.XData, "x values for Complex not updated"); + testCase.verifyNotEqual(oldlhComplex_YData, testCase.App.ConcViewObj.lhComplex.YData, "y values for Complex not updated"); + + % Check that lamp is set to false + testCase.verifyFalse(testCase.App.LampViewObj.IsOn); + + end % testChangeDosingAmountManualUpdate + + end +end \ No newline at end of file diff --git a/tests/testIsLeapYear.m b/tests/testIsLeapYear.m deleted file mode 100644 index c028ad2..0000000 --- a/tests/testIsLeapYear.m +++ /dev/null @@ -1,28 +0,0 @@ -classdef testIsLeapYear < matlab.unittest.TestCase - - properties (TestParameter) - yearAndIsLeapYear = { ... - {2000, true}; ... - {2024, true}; ... - {2025, false}; ... - {1985, false}; ... - {1999, false} }; - end - - methods (Test, ParameterCombination = "sequential") - - function test_isLeapYear(testCase, yearAndIsLeapYear) - - % Extract input and expected output from parameter for clarity - year = yearAndIsLeapYear{1}; - expected_isLeap = yearAndIsLeapYear{2}; - - % Exercise the code - actual_isLeap = isLeapYear(year); - - % Verify results - testCase.verifyEqual(actual_isLeap, expected_isLeap); - end - end -end - diff --git a/tests/testSimpleSort.m b/tests/testSimpleSort.m deleted file mode 100644 index 47d0ba2..0000000 --- a/tests/testSimpleSort.m +++ /dev/null @@ -1,90 +0,0 @@ -classdef testSimpleSort < matlab.unittest.TestCase - - properties (TestParameter) - inputValue = struct( ... - ScalarPositive = 5, ... - ScalarNegative = -7, ... - ScalarZero = 0, ... - VectorLength2 = [1649,42], ... - VectorLength10 = [90, 80, 74, 6, 8, 9, 80, 95, 69, 14], ... - VectorLength20 = [73, 12, 12, 65, 33, 66, 75, 59, 75, 24, ... - 74, 98, 87, 9, 37, 37, 69, 60, 79, 37], ... - Empty = []); - end - - methods (Test) - - function testSimpleSort_ExampleBasedTest(testCase) - % This is an example-based test using a hardcoded input and - % expected output - - % Define inputs - in = [3,5,2,8,1,2,6]; - - % Define expected outputs - expectedOut = [1,2,2,3,5,6,8]; - - % Exercise function - actualOut = simpleSort(in); - - % Verify results - testCase.verifyEqual(actualOut,expectedOut); - end - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % Below is a property-based test that is missing the logic to % - % test the properties of the result. Uncomment and update the % - % local functions at the bottom of the class to make it pass. % % - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % function testSimpleSort_PropertyBasedTest(testCase, inputValue) - % % Create a property-based test for simpleSort - % - % % Another way to test a code is by identifying "properties" - % % (i.e., characteristics) of the results it produces that stay - % % the same no matter what the input is. Once these properties - % % are identified, you can write tests that check these - % % properties against many different test inputs. Being able to - % % run tests against many different inputs (even randomly - % % generated inputs) can sometimes help you discover bugs and - % % edge cases that you might have missed with a smaller sample - % % of test inputs. - % - % % For simpleSort, the properties of the algorithm are: - % % - Output is sorted in ascending order - % % - Output has the same number of elements as the input - % - % - % % Exercise function - % result = simpleSort(inputValue); - % - % - % % Verify that the result is sorted in ascending order - % % INSTRUCTION: Fill out the "checkIsSortedAscending" local - % % function at the bottom of this file so that it - % % returns true when the result is sorted in - % % ascending order and false when it is not - % isSortedAscending = checkIsSortedAscending(result); - % testCase.verifyTrue(isSortedAscending); - % - % % Verify the result and inputValue have the same number of - % % elements - % % INSTRUCTION: Find an existing verification that compares - % % result against an expected number of elements - % % and replace ______ with that verification - % numElementsInput = numel(inputValue); - % testCase.verify______(result,numElementsInput); - % end - - end -end - -function isSortedAscending = checkIsSortedAscending(result) -% HOMEWORK: Add code to check if result is sorted in ascending order -% Note: isSortedAscending should be a logical true/false - -% ADD CODE HERE - - -end diff --git a/tests/tgenerateSimFun.m b/tests/tgenerateSimFun.m new file mode 100644 index 0000000..74933e1 --- /dev/null +++ b/tests/tgenerateSimFun.m @@ -0,0 +1,48 @@ +classdef tgenerateSimFun < matlab.unittest.TestCase + + properties + MATfilename = "test_generateSimFun.mat" + MATfilefullpath + LoadedData + end + + properties (TestParameter) + fieldName = {"simFun","doseTable","dependenciesSimFun"}; + end + + methods(Test) + + function testMATfileCreation(testCase) + % Verify that the MAT file is created + testCase.verifyTrue(isfile(testCase.MATfilefullpath), 'MAT file was not created.'); + end + + function testSimFunctionCreation(testCase, fieldName) + % Verify that the MAT file contains required fields + testCase.verifyTrue(isfield(testCase.LoadedData, fieldName), fieldName + " was not saved in " + testCase.MATfilename); + end + + %% Have attendees add this test? + function testSimFunctionAcceleration(testCase) + % Verify that the SimFunction is accelerated + testCase.verifyTrue(testCase.LoadedData.simFun.isAccelerated, "simFun was not accelerated."); + end + + end + + methods (TestClassSetup) + + function classSetup(testCase) + % Set up shared state for all tests. + + % Test if the simulation function is created successfully + testCase.MATfilefullpath = generateSimFun(testCase.MATfilename); + testCase.LoadedData = load(testCase.MATfilefullpath); + + % Tear down with testCase.addTeardown. + testCase.addTeardown(@delete,testCase.MATfilefullpath); + + end + + end +end \ No newline at end of file