From abf5026705a56f1166debbce2692bdb22291afca Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:30:03 +0100 Subject: [PATCH 01/77] Create codecov.yml --- .github/workflows/codecov.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/codecov.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000000..586d7c723e --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,32 @@ +name: Code Cov CI + +on: + push: + branches: [develop] # Trigger workflow on push to master + pull_request: + branches: [develop] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + # Install MATLAB and dependencies (assuming you're using the MATLAB GitHub Action) + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + with: + release: R2022a # Specify the MATLAB version you need + + # Run MATLAB tests from the /test directory + - name: Run MATLAB tests and generate coverage + run: | + matlab -batch "coverageReport = matlab.unittest.plugins.codecoverage.CoverageReport('coverage'); runtests('test', 'IncludeSubfolders', true, 'CoverageReport', coverageReport);" + + # Upload coverage report to Codecov + - name: Upload coverage to Codecov + run: | + bash <(curl -s https://codecov.io/bash) + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From bf11cf185857e9651725c0c3f2cb63b4ff7cd692 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:41:49 +0100 Subject: [PATCH 02/77] testing code cov --- test/test_myfunction.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/test_myfunction.m diff --git a/test/test_myfunction.m b/test/test_myfunction.m new file mode 100644 index 0000000000..602f106d1b --- /dev/null +++ b/test/test_myfunction.m @@ -0,0 +1,16 @@ +classdef test_myfunction < matlab.unittest.TestCase + methods(Test) + function testSimple(testCase) + % Dummy test for the function myfunction + result = myfunction(3); % Call the function defined below + expected = 9; + testCase.verifyEqual(result, expected); + end + end +end + +% The function to be tested +function y = myfunction(x) + % Simple function that squares the input + y = x^2; +end From 251b4004b267a328c3f44918c946955e654ff0f4 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:41:56 +0100 Subject: [PATCH 03/77] Update codecov.yml --- .github/workflows/codecov.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 586d7c723e..57c718faf7 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -13,16 +13,16 @@ jobs: steps: - uses: actions/checkout@v3 - # Install MATLAB and dependencies (assuming you're using the MATLAB GitHub Action) + # Set up MATLAB - name: Set up MATLAB uses: matlab-actions/setup-matlab@v1 with: - release: R2022a # Specify the MATLAB version you need + release: R2022a # Specify the MATLAB version - # Run MATLAB tests from the /test directory + # Run only the specific test_myfunction.m file from the /tests directory - name: Run MATLAB tests and generate coverage run: | - matlab -batch "coverageReport = matlab.unittest.plugins.codecoverage.CoverageReport('coverage'); runtests('test', 'IncludeSubfolders', true, 'CoverageReport', coverageReport);" + matlab -batch "coverageReport = matlab.unittest.plugins.codecoverage.CoverageReport('coverage'); runtests('tests/test_myfunction.m', 'CoverageReport', coverageReport);" # Upload coverage report to Codecov - name: Upload coverage to Codecov From 0fbd189306e5a49b9be96a9ad517ce6d251c739c Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:45:26 +0100 Subject: [PATCH 04/77] Update codecov.yml --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 57c718faf7..aedd643249 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -22,7 +22,7 @@ jobs: # Run only the specific test_myfunction.m file from the /tests directory - name: Run MATLAB tests and generate coverage run: | - matlab -batch "coverageReport = matlab.unittest.plugins.codecoverage.CoverageReport('coverage'); runtests('tests/test_myfunction.m', 'CoverageReport', coverageReport);" + matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('tests/test_myfunction.m')); assertSuccess(results);" # Upload coverage report to Codecov - name: Upload coverage to Codecov From 3af702e3ff0bcb114d1e2799a102a9ac780266ef Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:47:17 +0100 Subject: [PATCH 05/77] Update codecov.yml --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index aedd643249..cd534b4e83 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -22,7 +22,7 @@ jobs: # Run only the specific test_myfunction.m file from the /tests directory - name: Run MATLAB tests and generate coverage run: | - matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('tests/test_myfunction.m')); assertSuccess(results);" + matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('test/test_myfunction.m')); assertSuccess(results);" # Upload coverage report to Codecov - name: Upload coverage to Codecov From da60a5e71a4e89f3b52b059880059d28ee2a1f4c Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:27:24 +0100 Subject: [PATCH 06/77] Update codecov.yml --- .github/workflows/codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index cd534b4e83..3ac508760d 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,6 +27,7 @@ jobs: # Upload coverage report to Codecov - name: Upload coverage to Codecov run: | + coverage xml bash <(curl -s https://codecov.io/bash) env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 7ec87aa60cda05fe5b348b6d41c4633fffb2ed41 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:39:29 +0100 Subject: [PATCH 07/77] Update codecov.yml --- .github/workflows/codecov.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 3ac508760d..217ba2ede4 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -2,7 +2,7 @@ name: Code Cov CI on: push: - branches: [develop] # Trigger workflow on push to master + branches: [develop] # Trigger workflow on push to develop pull_request: branches: [develop] @@ -27,7 +27,6 @@ jobs: # Upload coverage report to Codecov - name: Upload coverage to Codecov run: | - coverage xml - bash <(curl -s https://codecov.io/bash) + bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 368adc70bdf51fedc2b958b4c8bd2b8c967b5ca6 Mon Sep 17 00:00:00 2001 From: rosieluo2021 Date: Sat, 19 Oct 2024 11:51:12 +0100 Subject: [PATCH 08/77] debug_testoutputNetworkCytoscape --- src/base/io/utilities/outputNetworkCytoscape.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/io/utilities/outputNetworkCytoscape.m b/src/base/io/utilities/outputNetworkCytoscape.m index 97ba0c9697..3a64fcdd29 100644 --- a/src/base/io/utilities/outputNetworkCytoscape.m +++ b/src/base/io/utilities/outputNetworkCytoscape.m @@ -119,7 +119,7 @@ fprintf(fidNodeType,'%s = rxn\n',model.rxns{rxnNo}); % Subsystems if (isfield(model,'subSystems')) - fprintf(fidSubSys,'%s = %s\n',model.rxns{rxnNo},strjoin(model.subSystems{rxnNo},';')); + fprintf(fidSubSys,'%s = %s\n',model.rxns{rxnNo},strjoin(model.subSystems(rxnNo),';')); end % Gene-reaction associations if (isfield(model,'genes')) From 163e045288a45a3935303ecd170206a6ed6c0a10 Mon Sep 17 00:00:00 2001 From: rosieluo2021 Date: Sat, 19 Oct 2024 11:54:11 +0100 Subject: [PATCH 09/77] debug_testfunctions --- src/reconstruction/refinement/mergeTwoModels.m | 10 ++++++---- .../base/testSolvers/createToyModelForLifting.m | 3 ++- .../testDynamicModelFieldModification.m | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/reconstruction/refinement/mergeTwoModels.m b/src/reconstruction/refinement/mergeTwoModels.m index fca791dad2..6d6bb51fc9 100644 --- a/src/reconstruction/refinement/mergeTwoModels.m +++ b/src/reconstruction/refinement/mergeTwoModels.m @@ -160,10 +160,12 @@ %Check, that there are no duplicated IDs in the primary key fields. ureacs = unique(modelNew.rxns); -% if ~(numel(modelNew.rxns) == numel(ureacs)) -% error(['The following reactions were present in both models but had distinct stoichiometries:\n',... -% strjoin(ureacs(cellfun(@(x) sum(ismember(modelNew.rxns,x)) > 1,ureacs)),', ')]); -% end +if ~(numel(modelNew.rxns) == numel(ureacs)) + warning(['The following reactions were present in both models but had distinct stoichiometries:\n',... + strjoin(ureacs(cellfun(@(x) sum(ismember(modelNew.rxns,x)) > 1,ureacs)),', ')]); + error(['The following reactions were present in both models but had distinct stoichiometries:\n',... + strjoin(ureacs(cellfun(@(x) sum(ismember(modelNew.rxns,x)) > 1,ureacs)),', ')]); +end if mergeGenes && (isfield(model1,'rxnGeneMat') || isfield(model2, 'rxnGeneMat')) %recreating the rxnGeneMat diff --git a/test/verifiedTests/base/testSolvers/createToyModelForLifting.m b/test/verifiedTests/base/testSolvers/createToyModelForLifting.m index aa7100413b..4e200b3351 100644 --- a/test/verifiedTests/base/testSolvers/createToyModelForLifting.m +++ b/test/verifiedTests/base/testSolvers/createToyModelForLifting.m @@ -25,7 +25,8 @@ %The model can have at most 0.01 units of CouplingMet. model = changeRxnBounds(model,'R4',1e-2,'u'); if ~Coupling - model = removeMetabolites(model,'CouplingMet'); + removeRxnFlag = 0; % only remove the metabolites but keep the reactions + model = removeMetabolites(model,'CouplingMet',removeRxnFlag); end %Add Exchangers diff --git a/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m b/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m index f520961e7d..c8cc95c9d4 100644 --- a/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m +++ b/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m @@ -120,8 +120,9 @@ %Assert that the right mets are removed and that the others are retained. assert(isempty(intersect(model2.mets,model.mets(removedMets))) && isempty(setxor(setdiff(model.mets,model.mets(removedMets)),model2.mets))) -%Now, remove a metabolite -model = removeMetabolites(model,model.mets{end}); +%Now, remove a metabolite but keep reactions +removeRxnFlag =0; +model = removeMetabolites(model,model.mets{end},removeRxnFlag); % and try this again (same sized rxns and mets) model2 = removeFieldEntriesForType(model,removedMets,'mets', length(model.mets)); reducedSMatrix = model.S; From f9868c05073d2411550196c25939baa6eea260e3 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Tue, 29 Oct 2024 09:37:09 +0000 Subject: [PATCH 10/77] Skip the CLP solver --- src/base/solvers/getSetSolver/changeCobraSolver.m | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/base/solvers/getSetSolver/changeCobraSolver.m b/src/base/solvers/getSetSolver/changeCobraSolver.m index 0dfac287dc..ccc5c7839b 100644 --- a/src/base/solvers/getSetSolver/changeCobraSolver.m +++ b/src/base/solvers/getSetSolver/changeCobraSolver.m @@ -537,12 +537,15 @@ problem = struct('A',[0 1],'b',0,'c',[1;1],'osense',-1,'F',speye(2),'lb',[0;0],'ub',[0;0],'csense','E','vartype',['C';'I'],'x0',[0;0]); end try - %This is the code that actually tests if a solver is working - if validationLevel>1 - %display progress - eval(['solveCobra' solverType '(problem,''printLevel'',3);']); - else - eval(['solveCobra' solverType '(problem,''printLevel'',0);']); + % Skip the CLP solver until further developments + if ~strcmp(solverType, 'CLP') + %This is the code that actually tests if a solver is working + if validationLevel>1 + %display progress + eval(['solveCobra' solverType '(problem,''printLevel'',3);']); + else + eval(['solveCobra' solverType '(problem,''printLevel'',0);']); + end end catch ME %This is the code that describes what went wrong if a call to a solver does not work From 479925c544326587daf1cb6cb864d532ce4a13d9 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 21:39:49 +0000 Subject: [PATCH 11/77] Update testMergeTwoModels.m --- .../testMergeTwoModels.m | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/verifiedTests/reconstruction/testModelManipulation/testMergeTwoModels.m b/test/verifiedTests/reconstruction/testModelManipulation/testMergeTwoModels.m index 822ef5c487..eee2e493dc 100644 --- a/test/verifiedTests/reconstruction/testModelManipulation/testMergeTwoModels.m +++ b/test/verifiedTests/reconstruction/testModelManipulation/testMergeTwoModels.m @@ -7,8 +7,17 @@ % Authors: % - Thomas Pfau 2018 +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + +% Initiate the test +fprintf(' -- Running testMergeTwoModels ... '); + % We will create 2 toy models -%model1 +% model1 model1 = createModel(); model1 = addMultipleMetabolites(model1,{'A[c]','B[c]','C[c]','D[c]','E[c]'},'metKEGGID',{'C1','C2','C3','C4','C5'}); model1 = addGenes(model1,{'G1','G2','G3'},'geneNames',{'Gene1','Gene2','Gene3'}); @@ -77,6 +86,13 @@ %Test appropriate error if there are duplicate ids with distinct %stoichiometries: model2 = addReaction(model2,'Rcommon','A[c] -> C[c]'); -assert(verifyCobraFunctionError('mergeTwoModels','outputArgCount',1,'inputs',{model1,model2},... - 'testMessage','The following reactions were present in both models but had distinct stoichiometries:\nRcommon')); +mergeTwoModels(model1, model2); + +assert(strcmp(lastwarn, 'The following reactions were present in both models but had distinct stoichiometries:\nRcommon')) + +fprintf('\nDone.\n'); +fprintf('testMergeTwoModels passed successfully.\n'); + +% change the directory +cd(currentDir); From 1a38c4f43ac1b2102444bf44ec06ba6223bdf1de Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 21:43:06 +0000 Subject: [PATCH 12/77] Update testSurfNet.m --- test/verifiedTests/analysis/testPrint/testSurfNet.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/verifiedTests/analysis/testPrint/testSurfNet.m b/test/verifiedTests/analysis/testPrint/testSurfNet.m index ec5d29b097..10f54ccdd2 100644 --- a/test/verifiedTests/analysis/testPrint/testSurfNet.m +++ b/test/verifiedTests/analysis/testPrint/testSurfNet.m @@ -18,6 +18,8 @@ fileDir = fileparts(which('testSurfNet')); cd(fileDir); +fprintf(' -- Running testSurfNet ... '); + model = getDistributedModel('ecoli_core_model.mat'); % generate flux data for testing @@ -134,7 +136,7 @@ score = ((match / numel(text1)) * (match / numel(text2))) ^ 0.5; fprintf('Compare the printed with the expected results ...\n') -assert(score > 1 - 1e-3); % some mismatches due to linebreaks and space +assert(score > 1 - 1e-2); % some mismatches due to linebreaks and space fprintf('\nSuccess. Finish testing normal functionalities of surfNet.\n') % check warnings @@ -296,5 +298,8 @@ assert(isequal(textSurfNet{1}, textSurfNet{2})) assert(isequal(textSurfNet{1}, textSurfNet{3})) +fprintf('Done.\n'); +fprintf('testSurfNet passed successfully.\n'); + % change the directory cd(currentDir) From eb378b3162bdb1661c8952afd4fb1aa39fc6a668 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 22:13:25 +0000 Subject: [PATCH 13/77] Update optimizeCbModel.m --- src/analysis/FBA/optimizeCbModel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/FBA/optimizeCbModel.m b/src/analysis/FBA/optimizeCbModel.m index 731bcdb1a9..347382a9e6 100644 --- a/src/analysis/FBA/optimizeCbModel.m +++ b/src/analysis/FBA/optimizeCbModel.m @@ -851,7 +851,7 @@ else solution.f1 = 0; end - solution.f2 = 0.5*solution.full'*optProblem.F*solution.full; + solution.f2 = 0.5*solution.full'*optProblem2.F*solution.full; if isfield(solution,'objQuadratic') solution.f2 = solution.objQuadratic; solution = rmfield(solution,'objQuadratic'); From 54bcff6385b0a3a029182200982ce9f55ca262b7 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 23:29:06 +0000 Subject: [PATCH 14/77] Update testSubspacing and checkScaling.m --- src/analysis/subspaces/checkScaling.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analysis/subspaces/checkScaling.m b/src/analysis/subspaces/checkScaling.m index 7459aa2220..26a85ac357 100644 --- a/src/analysis/subspaces/checkScaling.m +++ b/src/analysis/subspaces/checkScaling.m @@ -143,6 +143,8 @@ % determine the number of metabolites and reactions [nMets, nRxns] = size(A); + % Last column is model.b + nRxns = nRxns - 1; % determine the row and column scaling factors [cscale, rscale] = gmscale(A, 0, scltol); From 0b4d6ff643cb5d5a9a1d4e674511833bcba8e74e Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 23:39:20 +0000 Subject: [PATCH 15/77] Update checkScaling.m --- src/analysis/subspaces/checkScaling.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/analysis/subspaces/checkScaling.m b/src/analysis/subspaces/checkScaling.m index 26a85ac357..b8476d8864 100644 --- a/src/analysis/subspaces/checkScaling.m +++ b/src/analysis/subspaces/checkScaling.m @@ -142,9 +142,7 @@ % determine the number of metabolites and reactions - [nMets, nRxns] = size(A); - % Last column is model.b - nRxns = nRxns - 1; + [nMets, nRxns] = size(model.S); % determine the row and column scaling factors [cscale, rscale] = gmscale(A, 0, scltol); From db39094fdd66d8e300e96418b6c5783f5d082297 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Thu, 31 Oct 2024 23:44:05 +0000 Subject: [PATCH 16/77] Update testCycleFreeFlux.m --- test/verifiedTests/analysis/testThermo/testCycleFreeFlux.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/verifiedTests/analysis/testThermo/testCycleFreeFlux.m b/test/verifiedTests/analysis/testThermo/testCycleFreeFlux.m index f3fa0d3306..0106b4aed7 100644 --- a/test/verifiedTests/analysis/testThermo/testCycleFreeFlux.m +++ b/test/verifiedTests/analysis/testThermo/testCycleFreeFlux.m @@ -69,7 +69,7 @@ param.relaxBounds = false; % Default v2 = cycleFreeFlux(solution.v, model.c, model, isInternalRxn, param); d2 = v2 - solution.v; - assert(all(d2) <= tol*10); + assert(all(d2 <= tol*10)); param.relaxBounds = true; % Relax flux bounds that do not include 0 v3 = cycleFreeFlux(solution.v, model.c, model, isInternalRxn, param); From 9240b86f20d0391792f8ba5ae31994bdbb1a38cf Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 00:05:22 +0000 Subject: [PATCH 17/77] Bring back lrsOutputReadRay.m --- .../lrs/lrsInterface/lrsOutputReadRay.m | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/analysis/topology/extremeRays/lrs/lrsInterface/lrsOutputReadRay.m diff --git a/src/analysis/topology/extremeRays/lrs/lrsInterface/lrsOutputReadRay.m b/src/analysis/topology/extremeRays/lrs/lrsInterface/lrsOutputReadRay.m new file mode 100644 index 0000000000..38bcd063f9 --- /dev/null +++ b/src/analysis/topology/extremeRays/lrs/lrsInterface/lrsOutputReadRay.m @@ -0,0 +1,103 @@ +function [R, V] = lrsOutputReadRay(filename) +% Reads into matlab a vertex representation output from lrs +% +% USAGE: +% +% [R, V] = lrsOutputReadRay(filename) +% +% INPUT: +% filename: name of .ext file from lrs +% +% OUTPUT: +% R: `nDim` by `nRay` matrix of extreme rays +% V: `nDim` by `nVertex` matrix of vertices + +fid = fopen(filename); + +% pause(eps) +while 1 + tline = fgetl(fid); + if strcmp(tline, 'begin') + break; + elseif ~ischar(tline) + error('Could not read lrs output file.'); + end +end + +% find the number of columns +C = textscan(fid, '%s %f %s', 1); +nCols = C{2}; + +% move on pointer one line +fgetl(fid); + +% count the number of rows in the file +nRows = 0; +while 1 + if ~strcmp(fgetl(fid), 'end') + nRows = nRows + 1; + else + break; + end +end + +fclose(fid); + + +% pwd +fid = fopen(filename); + +while 1 + if strcmp(fgetl(fid), 'begin') + break; + end +end + +% find the number of columns +C = textscan(fid, '%s %f %s', 1); +nCols = C{2}; + +% move on pointer one line +fgetl(fid); + +% read rows into a matrix +P = sparse(nRows, nCols) + +for r = 1:nRows + line = fgetl(fid); + if isempty(findstr('/', line)) + scannedLine = sscanf(line, '%d')'; % added transpose here for reading in LP solutions + P(r, :) = scannedLine; + else + line = strrep(line, '/', '.'); + scannedLine = sscanf(line, '%f')'; + for c = 1:nCols + M = mod(scannedLine(c), 1); + if M ~= 0 + F = fix(scannedLine(c)); + scannedLine(c) = F / M; + else + scannedLine(c) = int16(scannedLine(c)); + end + end + % pause(eps); + end +end +fclose(fid); + +% Each vertex is given in the form +% 1 v0 v 1 ... vn-1 +V = P(P(:, 1) ~= 0, 2:end)'; + +% Each ray is given in the form +% 0 r0 r 1 ... rn-1 +R = P(P(:, 1) == 0, 2:end)'; % not the transpose + +% order the vertices by the number of nnz +[mlt, nlt] = size(R); +nNonZero = zeros(nlt, 1); +for n = 1:nlt + nNonZero(n) = nnz(R(:, n)); +end +[B, IX] = sort(nNonZero); +R = R(:, IX); From 6e432302e32b53c9b00ab21aa511534637d5805d Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 00:06:59 +0000 Subject: [PATCH 18/77] Update optimizeCbModel.m --- src/analysis/FBA/optimizeCbModel.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/FBA/optimizeCbModel.m b/src/analysis/FBA/optimizeCbModel.m index 347382a9e6..731bcdb1a9 100644 --- a/src/analysis/FBA/optimizeCbModel.m +++ b/src/analysis/FBA/optimizeCbModel.m @@ -851,7 +851,7 @@ else solution.f1 = 0; end - solution.f2 = 0.5*solution.full'*optProblem2.F*solution.full; + solution.f2 = 0.5*solution.full'*optProblem.F*solution.full; if isfield(solution,'objQuadratic') solution.f2 = solution.objQuadratic; solution = rmfield(solution,'objQuadratic'); From 2c57b7088affb6dc6f779e8f1cef5d8380bafa82 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 00:23:43 +0000 Subject: [PATCH 19/77] Update testReadSBML.m --- test/verifiedTests/base/testIO/testReadSBML.m | 1 + 1 file changed, 1 insertion(+) diff --git a/test/verifiedTests/base/testIO/testReadSBML.m b/test/verifiedTests/base/testIO/testReadSBML.m index 1e0af115ab..0dfcc77f83 100644 --- a/test/verifiedTests/base/testIO/testReadSBML.m +++ b/test/verifiedTests/base/testIO/testReadSBML.m @@ -119,6 +119,7 @@ model.genes = {'gene1'; 'gene2'}; model.rules = {''; ''}; model.rxnGeneMat = zeros(2, 2); + model.subSystems = {'s1'; 's2'} model = convertOldStyleModel(model); From 980157a593bae00a2dc49ffb09bf9659cbbf7eb7 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 01:07:16 +0000 Subject: [PATCH 20/77] Update testDynamicModelFieldModification.m --- .../testDynamicModelFieldModification.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m b/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m index f520961e7d..c58c49d182 100644 --- a/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m +++ b/test/verifiedTests/reconstruction/testModelManipulation/testDynamicModelFieldModification.m @@ -121,7 +121,7 @@ assert(isempty(intersect(model2.mets,model.mets(removedMets))) && isempty(setxor(setdiff(model.mets,model.mets(removedMets)),model2.mets))) %Now, remove a metabolite -model = removeMetabolites(model,model.mets{end}); +model = removeMetabolites(model,model.mets{end},'removeRxnFlag', 'legacy'); % and try this again (same sized rxns and mets) model2 = removeFieldEntriesForType(model,removedMets,'mets', length(model.mets)); reducedSMatrix = model.S; @@ -165,6 +165,7 @@ assert(isequal(e,e2)); %Compare irrespective of actual format. - +fprintf('Done\n') +fprintf('testDynamicModelFieldModification passed successfully\n') %Switch back cd(currentDir) From 0ec3d5bb45051f994ad6a2c13e6d02109f3f1d3c Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 13:32:53 +0000 Subject: [PATCH 21/77] Update testEFlux.m --- .../dataIntegration/testEFlux/testEFlux.m | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/verifiedTests/dataIntegration/testEFlux/testEFlux.m b/test/verifiedTests/dataIntegration/testEFlux/testEFlux.m index 74c420390c..a4c16728eb 100644 --- a/test/verifiedTests/dataIntegration/testEFlux/testEFlux.m +++ b/test/verifiedTests/dataIntegration/testEFlux/testEFlux.m @@ -6,10 +6,15 @@ % Author: % - Original file: Thomas Pfau -currentDir = pwd; + +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + % initialize the test -fileDir = fileparts(which('testEFlux.m')); -cd(fileDir); +fprintf(' -- Running testEFlux ...\n'); % requires access to GEO to download data. % Matlabs tolerances and precision seem incompatible for this function. @@ -64,4 +69,9 @@ assert(abs(fChangeNoise-fChangeOrig) < 1e-4); assert(stderr > 0) % this should could be wrong at some point, but it is so unlikely.... end -cd(currentDir) \ No newline at end of file + +% Print a success message +fprintf('Done.\n'); +fprintf('testEFlux passed successfully.\n'); + +cd(currentDir) From add0d6ab505ce0e26edc2717c64d5c941781925a Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 13:33:35 +0000 Subject: [PATCH 22/77] Update applyEFluxConstraints.m --- .../transcriptomics/eFlux/applyEFluxConstraints.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/dataIntegration/transcriptomics/eFlux/applyEFluxConstraints.m b/src/dataIntegration/transcriptomics/eFlux/applyEFluxConstraints.m index 003681f078..c33339ae77 100644 --- a/src/dataIntegration/transcriptomics/eFlux/applyEFluxConstraints.m +++ b/src/dataIntegration/transcriptomics/eFlux/applyEFluxConstraints.m @@ -62,11 +62,21 @@ expr.gene = expression.target; expr.value = expression.value; reactionExpression = mapExpressionToReactions(model, expr, minSum); + nanIDs = isnan(reactionExpression); + if any(nanIDs) + warning('eFlux assigns -1 value to No gene-expression data and orphan reaction expression') + reactionExpression(nanIDs) = -1; + end else %Default : unconstraint. reactionExpression = -ones(size(model.rxns)); [pres,pos] = ismember(model.rxns,expression.target); - reactionExpression(pres) = expression.target(pos(pres)); + reactionExpression(pres) = expression.target(pos(pres)); + nanIDs = isnan(reactionExpression); + if any(nanIDs) + warning('eFlux assigns -1 value to No gene-expression data and orphan reaction expression') + reactionExpression(nanIDs) = -1; + end end unconstraintReactions = reactionExpression == -1; @@ -102,4 +112,3 @@ constraintModel = model; end - From aced9f115c9a174aac658ed58be4d323005e43f0 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:08:45 +0000 Subject: [PATCH 23/77] Update findRxnsFromSubSystem.m --- .../exploration/findRxnsFromSubSystem.m | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/analysis/exploration/findRxnsFromSubSystem.m b/src/analysis/exploration/findRxnsFromSubSystem.m index 6920487269..37fe7ebf13 100644 --- a/src/analysis/exploration/findRxnsFromSubSystem.m +++ b/src/analysis/exploration/findRxnsFromSubSystem.m @@ -15,18 +15,29 @@ % rxnPos: A double array of positions of the reactions in % reactionNames in the model (same order). % -% USAGE: -% %Obtain all reactions with Glycolysis in their respective subSystems -% field. +% EXAMPLE: +% +% Obtain all reactions with Glycolysis in their respective subSystems +% field. % [reactionNames,rxnPos] = findRxnsFromSubSystem(model,'Glycolysis') % -% .. Author: - Thomas Pfau Nov 2017, Ronan MT. Fleming, 2022 +% .. Author: - Thomas Pfau Nov 2017, +% - Ronan MT. Fleming, 2022 +% - Farid Zare, 2024/08/14 updated the code to support rxn2subSystem field +% -charBool = cellfun(@(x) ischar(x), model.subSystems); -if all(charBool) - present = strcmp(model.subSystems,subSystem); -else - present = cellfun(@(x) any(ismember(x,subSystem)),model.subSystems); +% Check to see if model already has these fields +if ~isfield(model, 'rxn2subSystem') + warning('The "rxn2subSystem" field has been generated because it was not in the model.') + model = buildRxn2subSystem(model); end -reactionNames = model.rxns(present); -rxnPos = find(present); \ No newline at end of file + +% Get subSystem ids +subSystemID = ismember(model.subSystemNames, subSystem); + +% Get corresponding reactions +rxn2subSystemMat = model.rxn2subSystem(:, subSystemID); +rxnID = logical(sum(rxn2subSystemMat, 2)); + +reactionNames = model.rxns(rxnID); +rxnPos = find(rxnID); From dae9a8e5b886745a177799bc5864de93c456a04b Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:09:19 +0000 Subject: [PATCH 24/77] Update getModelSubSystems.m --- src/analysis/exploration/getModelSubSystems.m | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/analysis/exploration/getModelSubSystems.m b/src/analysis/exploration/getModelSubSystems.m index aaf887c19f..cc366c5d01 100644 --- a/src/analysis/exploration/getModelSubSystems.m +++ b/src/analysis/exploration/getModelSubSystems.m @@ -14,25 +14,58 @@ % subSystems in the model % % USAGE: -% %Get all subSystems present in the model. +% Get all subSystems present in the model. % [subSystems] = getModelSubSystems(model) % % .. Author: - Thomas Pfau Nov 2017 +% - Farid Zare March 2024 nested cells compatibility +% Check to see if subSystem elements are characters or cells if isfield(model, 'subSystems') cellBool = cellfun(@(x) iscell(x), model.subSystems); charBool = cellfun(@(x) ischar(x), model.subSystems); - if all(charBool) - subSystems = unique(model.subSystems); - elseif all(cellBool) - orderedSubs = cellfun(@(x) columnVector(x),model.subSystems,'UniformOUtput',false); - subSystems = setdiff(vertcat(orderedSubs{:}),''); - else - subSystems = unique(model.subSystems); + + % Check to see if the subSystem cell is a nested cell + nestedCells = false; + for i = 1:numel(model.subSystems) + if iscell(model.subSystems{i}) + nestedCells = true; + end end - if isempty(subSystems) - subSystems = {}; + + if ~nestedCells + if all(charBool) + subSystems = unique(model.subSystems); + elseif all(cellBool) + orderedSubs = cellfun(@(x) columnVector(x),model.subSystems,'UniformOUtput',false); + % Concatenate all sub-system names and exclude empty elements + subSystems = setdiff(vertcat(orderedSubs{:}),''); + else + subSystems = unique(model.subSystems); + end + if isempty(subSystems) + subSystems = {}; + end + + else + % In the case of nested cell format of sub-systems + subSystemVec = {}; + for i = 1:numel(model.subSystems) + if ischar(model.subSystems{i}) + subList = model.subSystems(i); + else + subList = model.subSystems{i}; + end + % turn it into a vertical vector if it is not + subList = columnVector(subList); + subSystemVec = [subSystemVec; subList]; + end + subSystems = unique(subSystemVec); end else subSystems = {}; -end \ No newline at end of file +end + +% Remove empty elements from sub-system name list +nonEmptyIndices = ~cellfun('isempty', subSystems); +subSystems = subSystems(nonEmptyIndices); From 0b7b4e09c09c775c7ce9196726f5b14ec784461b Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:10:39 +0000 Subject: [PATCH 25/77] Update isReactionInSubSystem.m --- .../exploration/isReactionInSubSystem.m | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/analysis/exploration/isReactionInSubSystem.m b/src/analysis/exploration/isReactionInSubSystem.m index 38668956d3..b4c0a92bc8 100644 --- a/src/analysis/exploration/isReactionInSubSystem.m +++ b/src/analysis/exploration/isReactionInSubSystem.m @@ -1,13 +1,13 @@ -function [present] = isReactionInSubSystem(model,reactions,subSystem) +function [present] = isReactionInSubSystem(model,reactions,subSystem) % Determine whether a reaction is in a given subSystem. % % USAGE: % -% [subSystems] = getModelSubSystems(model) +% [present] = isReactionInSubSystem(model,reactions,subSystem) % % INPUT: % model: A COBRA model struct with at least rxns and -% subSystems fields +% subSystems or rxn2subSystem(COBRA V4) fields % reactions: Either a string identifying a reaction, or a % cell array of strings identifying multiple % reactions, or a double vector identifying the @@ -16,22 +16,38 @@ % OUTPUT: % present: a boolean vector for each provided reaction. % -% USAGE: -% %Get all subSystems present in the model. -% [subSystems] = getModelSubSystems(model) % % .. Author: - Thomas Pfau Nov 2017 +% - Farid Zare 2024/08/14 support COBRA model V4 if ischar(reactions) reactions = {reactions}; end +if ischar(subSystem) + subSystem = {subSystem}; +end +if numel(subSystem) > 1 + error('This function can support only one subSystem as input') +end + +% Set defualt value +present = false(size(reactions)); + if iscell(reactions) - [~,reactions] = ismember(reactions,model.rxns); + [rxnID] = ismember(model.rxns, reactions); + [rxnExists] = ismember(reactions, model.rxns); +end + +% Check to see if model already has "rxn2subSystem" fields +if ~isfield(model, 'rxn2subSystem') + warning('The "rxn2subSystem" field has been generated because it was not in the model.') + model = buildRxn2subSystem(model); end -if isfield(model, 'subSystems') - present = cellfun(@(x) any(ismember(x,subSystem)),model.subSystems(reactions)); -else - present = false(numel(reactions)); -end \ No newline at end of file +% find subSystem from reactions +subSystemID = ismember(model.subSystemNames, subSystem); +rxn2subSystemMat = model.rxn2subSystem(rxnID, subSystemID); + +% Find existing reaction IDs +present(rxnExists) = logical(rxn2subSystemMat); From 8aec33a0cc3c43a7afcdef1d2320ae75c055987f Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:11:42 +0000 Subject: [PATCH 26/77] Create buildRxn2subSystem.m --- .../refinement/buildRxn2subSystem.m | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/reconstruction/refinement/buildRxn2subSystem.m diff --git a/src/reconstruction/refinement/buildRxn2subSystem.m b/src/reconstruction/refinement/buildRxn2subSystem.m new file mode 100644 index 0000000000..6e1aab03f0 --- /dev/null +++ b/src/reconstruction/refinement/buildRxn2subSystem.m @@ -0,0 +1,95 @@ +function [modelOut, rxn2subSystem, subSystemNames, nestedCells] = buildRxn2subSystem(model, removeSubSystems) +% Generates reaction-subSystem matrix for a COBRA model +% This function adds two fields to the COBRA model: 1) rxnSubsystemMat and +% 2)subSystemsNames and removes the old subSystems field(optional and can +% be set to false) +% +% USAGE: +% +% [modelOut, rxn2subSystem, subSystemNames, nestedCells] = buildRxn2subSystem(model, removeSubSystems) +% +% INPUTS: +% model: COBRA model structure +% +% OPTIONAL INPUTS: +% removeSubSystems: Binary variable, if equals to 1 (or true) subSystems +% field will be removed from the model default:true +% +% OUTPUTS: +% modelOut: COBRA model structure containing two added fields of +% "rxn2subSystem" and "subSystemsNames" +% rxn2subSystem: Matrix of reactions vs subSystems +% subSystemNames: Unique sub-system names in the model with order +% corrosponding to the matrix +% nestedCells: logical variable, True if sub-system field is a +% nested cell vector and False if it's not +% +% .. Authors: +% - Farid Zare 25 March 2024 +% + +% set optional input +if nargin < 2 + removeSubSystems = true; +elseif ~islogical(removeSubSystems) & removeSubSystems ~= 1 && removeSubSystems ~= 0 + error('removeSubSystem input should be logical variable true/false or 1/0') +end + +% Check to see if model already has these fields +if isfield(model, 'rxn2subSystem') + warning('rxn2subSystem matrix already exists in the model') +end + +if isfield(model, 'subSystemNames') + warning('subSystemNames field already exists in the model') +end + +% Error if there is no subSystems field in the model +if ~isfield(model, 'subSystems') + error('subSystems field should exist in the model') +end + +% Error if there is no rxns field in the model +if ~isfield(model, 'rxns') + error('rxns field should exist in the model') +end + +% Check if the sub-system cell is a nested cell variable +nestedCells = false; +nlt = numel(model.subSystems); +for i = 1:nlt + if iscell(model.subSystems{i}) + nestedCells = true; + end +end + +% Get model sub-system names +subSystemNames = getModelSubSystems(model); + +subsystemNum = numel(subSystemNames); +rxnNum = numel(model.rxns); + +% construct the matrix +rxn2subSystem = zeros(rxnNum, subsystemNum); + +for i = 1:rxnNum + % This line would work for char, cells and nested cell formats + if ischar(model.subSystems{i}) + subList = model.subSystems(i); + else + subList = model.subSystems{i}; + end + row = ismember(subSystemNames, subList); + rxn2subSystem(i,:) = row; +end + +% Assign two fields to the output model +modelOut = model; + +% Remove the subSystem field if it was set +if removeSubSystems + modelOut = rmfield(modelOut, 'subSystems'); +end + +modelOut.subSystemNames = subSystemNames; +modelOut.rxn2subSystem = rxn2subSystem; From 95914375c8259cdbc993ec0f8c55d65fcc294f62 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:12:20 +0000 Subject: [PATCH 27/77] Update isSameCobraModel.m --- .../refinement/isSameCobraModel.m | 88 +++++++++++++------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/src/reconstruction/refinement/isSameCobraModel.m b/src/reconstruction/refinement/isSameCobraModel.m index 3874276f98..17c3c713dc 100644 --- a/src/reconstruction/refinement/isSameCobraModel.m +++ b/src/reconstruction/refinement/isSameCobraModel.m @@ -20,8 +20,11 @@ % .. Authors: % - Markus Herrgard 9/14/07 % - CI integration: Laurent Heirendt - -%TODO this function needs updating to use structeq.m +% - Farid Zare 2024/08/12: New format of subSystems in the model +% +% Note: Notice that this function checks if two models are the same, two +% same models does not necessary mean two same structures. +% use structeq.m to compare two structures if ~exist('printLevel','var') printLevel = 0; @@ -55,6 +58,12 @@ isSame = false; end +% Check if subSystems field is nested cells +if isfield(model1, 'subSystems') || isfield(model2, 'subSystems') + [~, rxnSubSystemMat1, subSystemNames1, nestedCells1] = buildRxn2subSystem(model1); + [~, rxnSubSystemMat2, subSystemNames2, nestedCells2] = buildRxn2subSystem(model2); +end + % initialize variables nFields = length(commonFields); nDiff = zeros(nFields,1); @@ -65,43 +74,64 @@ value1 = getfield(model1, fieldName); value2 = getfield(model2, fieldName); - if 0 %debugging code - if strcmp(fieldName,'rxnConfidenceScores') - pause(0.1); + % Check if subSystems field is nested cells + if strcmp(fieldName, 'subSystems') && (nestedCells1 || nestedCells2) + % Compare subSystem names + nDiffSubName = sum(~strcmp(subSystemNames1, subSystemNames2)); + % Compare rxnSubSystem matrix + nDiffSubMat = ~isequal(rxnSubSystemMat1, rxnSubSystemMat2); + + if nDiffSubName > 0 + if printLevel > 0 + fprintf('Field %s differs in %d positions between the models\n',fieldName,nDiff(i)); end - end - % replace all whitespaces - if iscellstr(value1) - value1 = regexprep(value1, '[^\w'']', ''); - value2 = regexprep(value2, '[^\w'']', ''); - end + nDiff(i) = nDiffSubName; + elseif nDiffSubMat > 0 + if printLevel > 0 + fprintf('Nested cells in field subSystems: Shared lists, different contents per reaction.\n'); + end + nDiff(i) = nDiffSubMat; + end + else - if isnumeric(value1) - nDiff(i) = sum(sum(~((value1 == value2) | (isnan(value1) & isnan(value2))) )); - elseif iscellstr(value1) if 0 %debugging code - for i=1:length(value1) - if class(value1{i})~=class(value2{i}) - pause(0.1) + if strcmp(fieldName,'rxnConfidenceScores') + pause(0.1); end - if length(value1{i})~=length(value2{i}) - pause(0.1) + end + % replace all whitespaces + if iscellstr(value1) + value1 = regexprep(value1, '[^\w'']', ''); + value2 = regexprep(value2, '[^\w'']', ''); + end + + if isnumeric(value1) + nDiff(i) = sum(sum(~((value1 == value2) | (isnan(value1) & isnan(value2))) )); + elseif iscellstr(value1) + if 0 %debugging code + for i=1:length(value1) + if class(value1{i})~=class(value2{i}) + pause(0.1) + end + if length(value1{i})~=length(value2{i}) + pause(0.1) + end + end end + nDiff(i) = sum(~strcmp(value1, value2)); + elseif ischar(value1) + nDiff(i) = ~strcmp(value1, value2); end + + if printLevel > 0 + if nDiff(i) > 0 + fprintf('Field %s differs in %d positions between the models\n',fieldName,nDiff(i)); + end end - nDiff(i) = sum(~strcmp(value1, value2)); - elseif ischar(value1) - nDiff(i) = ~strcmp(value1, value2); + end if (nDiff(i) > 0) isSame = false; end - if printLevel > 0 - if nDiff(i) > 0 - fprintf('Field %s differs in %d positions between the models\n',fieldName,nDiff(i)); - end - end - - end From 3303202631d6158bdd1139e6b70a96f55792f8d6 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:13:04 +0000 Subject: [PATCH 28/77] Update testFindRxnsFromMets.m --- .../testExploration/testFindRxnsFromMets.m | 131 ++++++++---------- 1 file changed, 54 insertions(+), 77 deletions(-) diff --git a/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m b/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m index b5fe58eb42..ffdd3040fd 100644 --- a/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m +++ b/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m @@ -1,94 +1,71 @@ -% The COBRAToolbox: testFindRxnsFromMets.m +% The COBRAToolbox: testFindRxnsFromGenes.m % % Purpose: -% - Tests the functionality of findRxnFromMets with all available -% parameters +% - tests that reactions are found when providing a list of genes. +% - tests the correct functionality of findRxnFromGenes function % % Authors: -% - Original file: Thomas Pfau Jan 2018 -% +% - Original file: Stefania Magnusdottir August 2017 +% Samira Ranjbar -November 2023 (revise) + + +global CBTDIR % save the current path currentDir = pwd; % initialize the test -fileDir = fileparts(which('testFindRxnsFromMets')); +fileDir = fileparts(which('testFindRxnsFromGenes')); cd(fileDir); % load model model = getDistributedModel('ecoli_core_model.mat'); -% Initialize the test -fprintf(' -- Running testFindRxnsFromMets ... \n'); - -% First, find all reactions involved with 3pg -singleTestMet = model.mets{3}; -involvedReacs = {'Biomass_Ecoli_core_w_GAM';'PGK';'PGM'}; -consuming = involvedReacs; -producing = involvedReacs(2:3); -reacs = findRxnsFromMets(model,singleTestMet); -assert(isempty(setxor(involvedReacs,reacs))); -reacs = findRxnsFromMets(model,singleTestMet,'consumersOnly',true); -assert(isempty(setxor(consuming,reacs))); -reacs = findRxnsFromMets(model,singleTestMet,'producersOnly',true); -assert(isempty(setxor(producing,reacs))); - -% now, we change the bounds of PGK to not function in the forward direction -modelChanged = changeRxnBounds(model,'PGK',0,'l'); -modelChanged = changeRxnBounds(modelChanged,'PGM',0,'u'); -reacs = findRxnsFromMets(modelChanged,singleTestMet,'producersOnly',true); -assert(isempty(reacs)); - -% now, test the same with consumers and the PGM reaction, only biomass is -% left. -modelChanged = changeRxnBounds(model,'PGM',0,'l'); -modelChanged = changeRxnBounds(modelChanged,'PGK',0,'u'); -reacs = findRxnsFromMets(modelChanged,singleTestMet,'consumersOnly',true); -assert(isempty(setxor(involvedReacs(1),reacs))); - -% lets test 2 metabolites (2pg and 3pg) -dualTestMet = model.mets(2:3); -involvedReacs = {'Biomass_Ecoli_core_w_GAM';'ENO';'PGM';'PGK'}; -consuming = involvedReacs; -producing = involvedReacs(2:4); -reacs = findRxnsFromMets(model,dualTestMet); -assert(isempty(setxor(involvedReacs,reacs))); -reacs = findRxnsFromMets(model,dualTestMet,'consumersOnly',true); -assert(isempty(setxor(consuming,reacs))); -reacs = findRxnsFromMets(model,dualTestMet,'producersOnly',true); -assert(isempty(setxor(producing,reacs))); - -% test printout. -% build comparison text -res = printRxnFormula(model,'PGM'); -compText = res{1}; % this is sufficient; - -% create diary -diaryFile = 'RxnsFromMetTest'; -diary(diaryFile) -reacs = findRxnsFromMets(model,dualTestMet,'containsAll',true,'printFlag',1); -assert(isempty(setxor({'PGM'},reacs))); -diary off -text = importdata(diaryFile); -assert(~isempty(strfind(strrep(text,'\n',''),compText))); -%cleanup -delete(diaryFile); - - -% test implicit printOut is silent, if no output is created -diary(diaryFile) -[reacs,forms] = findRxnsFromMets(model,dualTestMet,'containsAll',true); -diary off; -text = importdata(diaryFile); -% ITs not found in the output -assert(isempty(strfind(text,compText))); -% but is equal to printRxnFormula -assert(isequal(forms,res)) -%cleanup -delete(diaryFile); - -% Print a success message -fprintf('Done.\n'); +% convert to new style model +model = convertOldStyleModel(model); + +% get reactions for gene list, include gene not in model and nested cell +geneList = {'b0115'; {'b0722'; 'MadeUp'}}; + +% Initiate the test +fprintf(' -- Running testFindRxnsFromGenes ... '); + +[geneRxnsStruct, geneRxnsArray] = findRxnsFromGenes(model, geneList, 0, 1); + +%Check warning message +warningmessage = lastwarn; +assert(strfind(warningmessage,'MadeUp')>0); +assert(isempty(strfind(warningmessage,'b0722'))); +assert(isempty(strfind(warningmessage,'b0115'))); + + +% find gene indeces of genes in model +geneInd = find(ismember(model.genes, {'b0115'; 'b0722'})); + +% manually find reactions associated with gene +rxnInds = []; +for i = 1:length(geneInd) + rxnInds = union(rxnInds, ... + find(~cellfun(@isempty, strfind(model.rules, ['x(', num2str(geneInd(i)), ')'])))); +end + +% check that result array has correct size and rxns +assert(size(geneRxnsArray, 1) == length(rxnInds)) +assert(size(geneRxnsArray, 2) == 6) +assert(isequal(geneRxnsArray(:, 1), model.rxns(rxnInds))) +assert(isequal(geneRxnsArray(:, 6), strcat('gene_', model.genes(geneInd)))) + +% check that result structure has correct size and rxns +for i = 1:length(geneInd) + geneRxns = (geneRxnsStruct.(['gene_', model.genes{geneInd(i)}])); + rxnInds = find(~cellfun(@isempty, strfind(model.rules, ['x(', num2str(geneInd(i)), ')']))); + assert(size(geneRxns, 1) == length(rxnInds)) + assert(size(geneRxns, 2) == 5) + assert(isequal(geneRxns(:, 1), model.rxns(rxnInds))) +end % change the directory cd(currentDir) + +% output a success message +fprintf('Done.\n'); From fe2faf26410a1f2eea9faa4e5e6cb816cc870706 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:14:14 +0000 Subject: [PATCH 29/77] Create testFindRxnsFromSubSystem.m --- .../testFindRxnsFromSubSystem.m | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/verifiedTests/analysis/testFindRxnsFromSubSystem/testFindRxnsFromSubSystem.m diff --git a/test/verifiedTests/analysis/testFindRxnsFromSubSystem/testFindRxnsFromSubSystem.m b/test/verifiedTests/analysis/testFindRxnsFromSubSystem/testFindRxnsFromSubSystem.m new file mode 100644 index 0000000000..7f49976e30 --- /dev/null +++ b/test/verifiedTests/analysis/testFindRxnsFromSubSystem/testFindRxnsFromSubSystem.m @@ -0,0 +1,46 @@ +% The COBRAToolbox: .m +% +% Purpose: +% - This test checks the correct functionality of findRxnsFromSubSystem +% +% Authors: +% - Farid Zare 2024/08/12 +% + +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + +% Create a Toy model +model = createToyModel(0, 0, 0); + +% Add subSystems field +subSystemsCell = {''; 'S1'; {'S1'; 'S2'}; 'S3'; {'S3'; 'S1'}; ''}; +model.subSystems = subSystemsCell; + +% Load reference data +rxnPosref = [3; 4; 5]; +reactionNamesref = {'R3'; 'R4'; 'R5'}; +nestedCellsref = true; + +fprintf(' -- Running testFindRxnsFromSubSystem ...\n '); +subSystem = {'S2', 'S3'}; +[reactionNames,rxnPos] = findRxnsFromSubSystem(model,subSystem); + +assert(isequal(reactionNames, reactionNamesref)) +assert(isequal(rxnPos, rxnPosref)) + +% Check to see if the code supports a COBRA model V4 +model = buildRxn2subSystem(model); +[reactionNames,rxnPos] = findRxnsFromSubSystem(model,subSystem); + +assert(isequal(reactionNames, reactionNamesref)) +assert(isequal(rxnPos, rxnPosref)) + +% output a success message +fprintf('Done.\n'); + +% change the directory +cd(currentDir) From cbb5b64bcab7067eb6dd646dd1f135bb28ea2918 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:15:07 +0000 Subject: [PATCH 30/77] Create testGetModelSubSystems.m --- .../testGetModelSubSystems.m | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 test/verifiedTests/analysis/testGetModelSubSystems/testGetModelSubSystems.m diff --git a/test/verifiedTests/analysis/testGetModelSubSystems/testGetModelSubSystems.m b/test/verifiedTests/analysis/testGetModelSubSystems/testGetModelSubSystems.m new file mode 100644 index 0000000000..d072535fd0 --- /dev/null +++ b/test/verifiedTests/analysis/testGetModelSubSystems/testGetModelSubSystems.m @@ -0,0 +1,62 @@ +% The COBRAToolbox: testGetModelSubSystems.m +% +% Purpose: +% - This test function checks the functionality of getModelSubSystems +% function +% +% Authors: +% - Farid Zare 2024/08/12 +% + + +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + +% Expected answer for subSystems: +refsubSystems = {'Anaplerotic reactions'; 'Citric Acid Cycle'; 'Exchange'; ... + 'Glutamate Metabolism'; 'Glycolysis/Gluconeogenesis'; ... + 'Inorganic Ion Transport and Metabolism'; 'Oxidative Phosphorylation';... + 'Pentose Phosphate Pathway'; 'Pyruvate Metabolism'; 'Transport, Extracellular'}; + +% load the model +model = getDistributedModel('ecoli_core_model.mat'); %For all models in the test/models folder and subfolders + +fprintf(' -- Running testGetModelSubSystems ... '); + +% test with character elements as sub-system names +[subSystems] = getModelSubSystems(model); +assert(isequal(subSystems, refsubSystems)); + +% test with cell elements as sub-system names +modelNew = model; +% Convert char elements to cell elements +for i = 1:numel(modelNew.subSystems) + modelNew.subSystems{i} = modelNew.subSystems(i); +end +[subSystems] = getModelSubSystems(modelNew); +assert(isequal(subSystems, refsubSystems)); + +% test with nested cell arrays +modelNew = model; +% Convert char elements to nested cell arrays +for i = 1:numel(modelNew.subSystems) + modelNew.subSystems{i} = [model.subSystems(i); model.subSystems(i)]; +end +[subSystems] = getModelSubSystems(modelNew); +assert(isequal(subSystems, refsubSystems)); + +% test a model with no subSystem field +modelNew = rmfield(modelNew, 'subSystems'); + +% Expected output is an empty cell +[subSystems] = getModelSubSystems(modelNew); +assert(isempty(subSystems)); + +% output a success message +fprintf('Done.\n'); + +% change the directory +cd(currentDir) From 55fc438ca78a4aad20a54f7801a8cd6d49c8d31a Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:16:06 +0000 Subject: [PATCH 31/77] Create testIsReactionInSubSystem.m --- .../testIsReactionInSubSystem.m | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m diff --git a/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m new file mode 100644 index 0000000000..0d47adb311 --- /dev/null +++ b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m @@ -0,0 +1,49 @@ +% The COBRAToolbox: .m +% +% Purpose: +% - This test checks the correct functionality of isReactionInSubSystem +% +% Authors: +% - Farid Zare 2024/08/14 +% + +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + +% Create a Toy model +model = createToyModel(0, 0, 0); + +% Add subSystems field +subSystemsCell = {''; 'S1'; {'S1'; 'S2'}; 'S3'; {'S3'; 'S1'}; ''}; +model.subSystems = subSystemsCell; + +% Load reference data +presentref = [0 1 1]; + +% Initiate the test +fprintf(' -- Running testIsReactionInSubSystem ... \n'); + +[present] = isReactionInSubSystem(model, {'Ex_A', 'R4', 'R5'}, {'S3'}); +assert(isequal(present, presentref)) + +% Test vertical input +[present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, {'S3', 'S2'}); +presentref = [0; 1; 1]; +assert(isequal(present, presentref)) + +% Test subSystem as a string input +[present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, 'S3'); +assert(isequal(present, presentref)) + +% Test COBRA V4 model +model = buildRxn2subSystem(model); +[present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, 'S3'); +assert(isequal(present, presentref)) + +% output a success message +fprintf('Done.\n'); +% change the directory +cd(currentDir) From 511b9f0bccc109b6ee86fe36025b52c76607b499 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:16:44 +0000 Subject: [PATCH 32/77] Update testWriteSBML.m --- test/verifiedTests/base/testIO/testWriteSBML.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/verifiedTests/base/testIO/testWriteSBML.m b/test/verifiedTests/base/testIO/testWriteSBML.m index a1c5eb05d6..3ad2c61858 100644 --- a/test/verifiedTests/base/testIO/testWriteSBML.m +++ b/test/verifiedTests/base/testIO/testWriteSBML.m @@ -14,6 +14,8 @@ % initialize the test fileDir = fileparts(which('testWriteSBML')); cd(fileDir); +fprintf('-- Running testWriteSBML ...'); + testModelXML = readCbModel('Ec_iJR904.xml'); @@ -33,7 +35,7 @@ testModelXML = rmfield(testModelXML,'rxnReferences'); % check whether both models are the same - [isSame numDiff fieldNames] = isSameCobraModel(testModelXML, testModelSBML); + [isSame numDiff fieldNames] = isSameCobraModel(testModelXML, testModelSBML, 1); % assess any potential differences assert(~any(numDiff)) @@ -65,3 +67,5 @@ catch % pass end + +fprintf('testWriteSBML passed!\n'); From 435c69d010a14f3852ffbcfc469f5268ad1f9311 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Fri, 1 Nov 2024 18:17:35 +0000 Subject: [PATCH 33/77] Create testBuildRxn2subSystem.m --- .../testBuildRxn2subSystem.m | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 test/verifiedTests/reconstruction/testBuildRxnSubSystem/testBuildRxn2subSystem.m diff --git a/test/verifiedTests/reconstruction/testBuildRxnSubSystem/testBuildRxn2subSystem.m b/test/verifiedTests/reconstruction/testBuildRxnSubSystem/testBuildRxn2subSystem.m new file mode 100644 index 0000000000..f9fec3f89d --- /dev/null +++ b/test/verifiedTests/reconstruction/testBuildRxnSubSystem/testBuildRxn2subSystem.m @@ -0,0 +1,40 @@ +% The COBRAToolbox: .m +% +% Purpose: +% - This test checks the correct functionality of buildRxn2subSystem +% +% Authors: +% - Farid Zare 2024/08/12 +% + +% save the current path and initialize the test +currentDir = cd(fileparts(which(mfilename))); + +% determine the test path for references +testPath = pwd; + +% Create a Toy model +model = createToyModel(0, 0, 0); + +% Add subSystems field +subSystemsCell = {''; 'S1'; {'S1'; 'S2'}; 'S3'; {'S3'; 'S1'}; ''}; +model.subSystems = subSystemsCell; + +% Load reference data +rxnSubSystemMatref = [0 0 0; 1 0 0; 1 1 0; 0 0 1; 1 0 1; 0 0 0]; +subSystemNamesref = {'S1'; 'S2'; 'S3'}; +nestedCellsref = true; + +fprintf(' -- Running testBuildRxnSubSystemMat ... '); + +[modelOut, rxnSubSystemMat, subSystemNames, nestedCells] = buildRxn2subSystem(model); + +assert(isequal(subSystemNames, subSystemNamesref)) +assert(isequal(rxnSubSystemMat, rxnSubSystemMatref)) +assert(nestedCells, nestedCellsref) + +% output a success message +fprintf('Done.\n'); + +% change the directory +cd(currentDir) From 1d2fcc03f95a3121873fef14679b8e03e288e349 Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 11:53:58 +0000 Subject: [PATCH 34/77] Update subsystem tests --- src/analysis/exploration/isReactionInSubSystem.m | 12 ++++++------ .../testIsReactionInSubSystem.m | 13 +++++++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/analysis/exploration/isReactionInSubSystem.m b/src/analysis/exploration/isReactionInSubSystem.m index b4c0a92bc8..fa3e08eed7 100644 --- a/src/analysis/exploration/isReactionInSubSystem.m +++ b/src/analysis/exploration/isReactionInSubSystem.m @@ -27,9 +27,9 @@ if ischar(subSystem) subSystem = {subSystem}; end -if numel(subSystem) > 1 - error('This function can support only one subSystem as input') -end +% if numel(subSystem) > 1 +% error('This function can support only one subSystem as input') +% end % Set defualt value present = false(size(reactions)); @@ -40,8 +40,8 @@ end % Check to see if model already has "rxn2subSystem" fields -if ~isfield(model, 'rxn2subSystem') - warning('The "rxn2subSystem" field has been generated because it was not in the model.') +if ~isfield(model, 'rxn2subSystem') || ~isfield(model, 'subSystemNames') + warning('"rxn2subSystem" or "subSystemNames" fields has been generated because they did not exist in the model.') model = buildRxn2subSystem(model); end @@ -50,4 +50,4 @@ rxn2subSystemMat = model.rxn2subSystem(rxnID, subSystemID); % Find existing reaction IDs -present(rxnExists) = logical(rxn2subSystemMat); +present(rxnExists) = logical(sum(rxn2subSystemMat, 2)); diff --git a/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m index 0d47adb311..751bd6c6a7 100644 --- a/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m +++ b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m @@ -20,30 +20,35 @@ subSystemsCell = {''; 'S1'; {'S1'; 'S2'}; 'S3'; {'S3'; 'S1'}; ''}; model.subSystems = subSystemsCell; -% Load reference data -presentref = [0 1 1]; - % Initiate the test fprintf(' -- Running testIsReactionInSubSystem ... \n'); [present] = isReactionInSubSystem(model, {'Ex_A', 'R4', 'R5'}, {'S3'}); +% set expected output +presentref = [0 1 1]; assert(isequal(present, presentref)) % Test vertical input -[present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, {'S3', 'S2'}); +[present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, {'S2', 'S3'}); +% set expected output presentref = [0; 1; 1]; assert(isequal(present, presentref)) % Test subSystem as a string input [present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, 'S3'); +% set expected output +presentref = [0; 1; 1]; assert(isequal(present, presentref)) % Test COBRA V4 model model = buildRxn2subSystem(model); [present] = isReactionInSubSystem(model, {'Ex_A'; 'R4'; 'R5'}, 'S3'); +% set expected output +presentref = [0; 1; 1]; assert(isequal(present, presentref)) % output a success message +fprintf('... testIsReactionInSubSystem passed...\n') fprintf('Done.\n'); % change the directory cd(currentDir) From fdf726d8db60c25df9e07e01a431511ad0821a49 Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 11:58:00 +0000 Subject: [PATCH 35/77] Update subSystem codes --- src/analysis/exploration/isReactionInSubSystem.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/analysis/exploration/isReactionInSubSystem.m b/src/analysis/exploration/isReactionInSubSystem.m index fa3e08eed7..066cbcd925 100644 --- a/src/analysis/exploration/isReactionInSubSystem.m +++ b/src/analysis/exploration/isReactionInSubSystem.m @@ -27,9 +27,6 @@ if ischar(subSystem) subSystem = {subSystem}; end -% if numel(subSystem) > 1 -% error('This function can support only one subSystem as input') -% end % Set defualt value present = false(size(reactions)); From 3e735a5412b94bfc7d6ade45151347cc249001ad Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 12:10:44 +0000 Subject: [PATCH 36/77] update reference data --- .../refData_determineBinaryMatrix.mat | Bin 1607 -> 681 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/verifiedTests/analysis/testSubspaces/refData_determineBinaryMatrix.mat b/test/verifiedTests/analysis/testSubspaces/refData_determineBinaryMatrix.mat index 3537055096082b1fd8d285d26ebba5921dee33fb..94fb29a8672c09d5b2a62095f31945c3ec96f9d6 100644 GIT binary patch delta 548 zcmX@kvyyd!ypFG_RB9*FtSiEG_f+Zv@$SKFfuT- zm>8%$F@bGji9mfi0|P_FoX5!t2?7Zz2?@-XWE{?D9XN1+ebK_2GL5q*4jdAgGckfm zXnR5fgPTSgQ&O7BEY?-?c~|kxgEn zW!v$C?&9i8p0ug=9$MCOeYI>=t?{|!01%F z;kdu@6-I_9wLI%V#(N@+hr3w7Onb`t4!7s35VtlwQI#lQp0I~&%Gr(Q38Gi!^l|BDU1xB4e$pIjX*;T*3b}ZYz`WsjZ6xhH42Cl1r%wjI{*N&_ouHA ziLF3yD1I2yTXz5szYi+1f^M@6jT+J7L7I1Iy%$j+O(wIHR-&NOe_(6~DoEoRoi~*& zRI(UNB-ARU|3##wAa^R8tq$SZ&7cV2u(=Ed`JHz8kB9u9KQm#`qmXet!>*4QCl8e( z-tgA~18-$M$G;|~t(^{4I9YbkE>}4OdBXLOO#+(9luWQE0o7f|*nOH%e&Fp^@%z$2L2dgaL{8@9StG6njYM|A6|{4V&bsXcEbX_%%~ zJM;%jLPfn%(zz%7s?!n2}OAW3<)%v0S#p>Bze-yDHRd z&E*5Pf$Gu2=*gtmiWfnbDM`8$C0+uif>#a(>OsjmMtjn_az(pnrtC^nr|-bTw`D*={zbIJy1 zKl-rATWdVaj;y9Cc;x1DjMv~_5M%=*3p8K%S>(%yJ@%1c;7O(o{IGZKg8^nVT}r7e@gndbGn8 z;i<+%DR^2FU&#!qPs`#TZiPRiIfo;>B{59B@MDvZO(xZPMch)Nh;JSX@lDlUfp$u$ zGT|i>mznM>2oZ2eAx!AUp&wmQK^+K(S16qbemOjW6|C zh}x^!&i=(E2Uq(hNY>=65^FZDgN3{60ixjJLcU9I06T?f!W$Vn%6Jl z6#rSX8{vps_`9Rl(g;g>#{QCAGD9kCB{j2nq}}N2ALq?;=FrHm!tV** zZIJ~w-?A{dF=jl4{w%Vdr1~Hy?f}jhahoQKK%pq CN~Bf* From cd3f8ec523ed2e8ede7081ea2b4136b0aa6e2510 Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 15:40:41 +0000 Subject: [PATCH 37/77] Update subsystem functions --- src/analysis/exploration/isReactionInSubSystem.m | 10 +++++++++- .../testIsReactionInSubSystem.m | 2 +- .../testModelManipulation/testSubSystemModification.m | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/analysis/exploration/isReactionInSubSystem.m b/src/analysis/exploration/isReactionInSubSystem.m index 066cbcd925..9a070a7cd9 100644 --- a/src/analysis/exploration/isReactionInSubSystem.m +++ b/src/analysis/exploration/isReactionInSubSystem.m @@ -29,13 +29,21 @@ end % Set defualt value -present = false(size(reactions)); +present = false(numel(reactions), 1); if iscell(reactions) [rxnID] = ismember(model.rxns, reactions); [rxnExists] = ismember(reactions, model.rxns); end +if isnumeric(reactions) + if max(reactions) > numel(model.rxns) + error('Index of reactions exceeds number of reactions in the model'); + end + rxnID = reactions; + rxnExists = true(size(reactions)); +end + % Check to see if model already has "rxn2subSystem" fields if ~isfield(model, 'rxn2subSystem') || ~isfield(model, 'subSystemNames') warning('"rxn2subSystem" or "subSystemNames" fields has been generated because they did not exist in the model.') diff --git a/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m index 751bd6c6a7..d8f60f1787 100644 --- a/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m +++ b/test/verifiedTests/analysis/testIsReactionInSubSystem/testIsReactionInSubSystem.m @@ -25,7 +25,7 @@ [present] = isReactionInSubSystem(model, {'Ex_A', 'R4', 'R5'}, {'S3'}); % set expected output -presentref = [0 1 1]; +presentref = [0; 1; 1]; assert(isequal(present, presentref)) % Test vertical input diff --git a/test/verifiedTests/reconstruction/testModelManipulation/testSubSystemModification.m b/test/verifiedTests/reconstruction/testModelManipulation/testSubSystemModification.m index 93f6299c2f..360efcff78 100644 --- a/test/verifiedTests/reconstruction/testModelManipulation/testSubSystemModification.m +++ b/test/verifiedTests/reconstruction/testModelManipulation/testSubSystemModification.m @@ -68,5 +68,8 @@ assert(all(isReactionInSubSystem(model,model.rxns(4:5),'Citric Acid Cycle'))); assert(isequal(isReactionInSubSystem(model,21:-1:18,'Exchange'),[true; true; false; false])); +% output a success message +fprintf('... testSubSystemModification passed...\n') +fprintf('Done.\n'); %Return to old path cd(currentDir) \ No newline at end of file From a90be109177df0b85771bd71c2e1e8e760019919 Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 17:25:49 +0000 Subject: [PATCH 38/77] Update Efm functions and testinf --- src/base/io/utilities/writeSBML.m | 2 +- src/visualization/efmviz/efmSubmodelExtractionAsSBML.m | 2 +- .../testEFMviz/testEfmSubmodelExtractionAsSBML.m | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/base/io/utilities/writeSBML.m b/src/base/io/utilities/writeSBML.m index ea4c1152d0..a405798167 100644 --- a/src/base/io/utilities/writeSBML.m +++ b/src/base/io/utilities/writeSBML.m @@ -131,7 +131,7 @@ if isfield(model,'modelAnnotation') tmp_anno = '
'; for i = 1 : length(model.modelAnnotation) - tmp_anno = strcat( tmp_anno,'

' ,model.modelAnnotation{i}, '

'); + tmp_anno = strcat( tmp_anno,'

' ,model.modelAnnotation(i), '

'); end tmp_anno = strcat(tmp_anno,'
'); sbmlModel.annotation = tmp_anno; diff --git a/src/visualization/efmviz/efmSubmodelExtractionAsSBML.m b/src/visualization/efmviz/efmSubmodelExtractionAsSBML.m index 829a610164..b8ae7786a7 100644 --- a/src/visualization/efmviz/efmSubmodelExtractionAsSBML.m +++ b/src/visualization/efmviz/efmSubmodelExtractionAsSBML.m @@ -47,7 +47,7 @@ listOfAbundantMets = vertcat(temp{:}); % Remove metabolites and unused genes, if any - modelEFM = removeMetabolites(modelEFM, listOfAbundantMets, true); + modelEFM = removeMetabolites(modelEFM, listOfAbundantMets, true, 'legacy'); end % the unused genes in the model do not get removed, so remove mannually diff --git a/test/verifiedTests/visualization/testEFMviz/testEfmSubmodelExtractionAsSBML.m b/test/verifiedTests/visualization/testEFMviz/testEfmSubmodelExtractionAsSBML.m index a3ec370621..c596caf2d3 100644 --- a/test/verifiedTests/visualization/testEFMviz/testEfmSubmodelExtractionAsSBML.m +++ b/test/verifiedTests/visualization/testEFMviz/testEfmSubmodelExtractionAsSBML.m @@ -15,6 +15,8 @@ % determine the test path for references testPath = pwd; +fprintf('-- Running testEfmSubmodelExtractionAsSBML ...'); + % load the model model = readCbModel('testModel.mat','modelName','model_irr'); %For all models which are part of this particular test. @@ -34,3 +36,6 @@ % Case 3: Test whether efmSubmodelExtractionAsSBML gives an error with < 3 input and 1 output arguments assert(verifyCobraFunctionError('efmSubsystemsExtraction', 'inputs', {model, selectedRxns}, 'outputArgCount', 1)); assert(verifyCobraFunctionError('efmSubsystemsExtraction', 'inputs', {model}, 'outputArgCount', 1)); + +fprintf('testEfmSubmodelExtractionAsSBML passed!\n'); +fprintf('Done.\n') \ No newline at end of file From ad52ef2fa33eacb3718dcda854e875f6390c72ef Mon Sep 17 00:00:00 2001 From: farid Date: Sat, 2 Nov 2024 18:46:33 +0000 Subject: [PATCH 39/77] Update testuFBA --- test/verifiedTests/analysis/testuFBA/testuFBA.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/verifiedTests/analysis/testuFBA/testuFBA.m b/test/verifiedTests/analysis/testuFBA/testuFBA.m index 08af90d64a..ff98001318 100644 --- a/test/verifiedTests/analysis/testuFBA/testuFBA.m +++ b/test/verifiedTests/analysis/testuFBA/testuFBA.m @@ -96,7 +96,7 @@ % Test output sol = optimizeCbModel(uFBAoutput.model); - solassert(sol.f > 0.225 & sol.f < 0.235, 'Solution incorrect to 2 decimals.') + assert(sol.f > 0.143 & sol.f < 0.15, 'Solution incorrect to 2 decimals.') else fprintf('This test requires Gurobi to run properly') end From 275486819270a1a94137c76603771ced5659e4fd Mon Sep 17 00:00:00 2001 From: farid Date: Sun, 3 Nov 2024 09:27:07 +0000 Subject: [PATCH 40/77] Update Polytope sampling functions --- .../PolytopeSimplifier/TwoSidedBarrier.m | 310 ++++++++++-------- .../PolytopeSimplifier/standardize_problem.m | 28 +- .../BarrierRound/utils/TableDisplay.m | 208 ++++++------ test/models | 2 +- tutorials | 2 +- 5 files changed, 302 insertions(+), 248 deletions(-) diff --git a/src/analysis/sampling/BarrierRound/PolytopeSimplifier/TwoSidedBarrier.m b/src/analysis/sampling/BarrierRound/PolytopeSimplifier/TwoSidedBarrier.m index ec750dc497..d979d98637 100644 --- a/src/analysis/sampling/BarrierRound/PolytopeSimplifier/TwoSidedBarrier.m +++ b/src/analysis/sampling/BarrierRound/PolytopeSimplifier/TwoSidedBarrier.m @@ -1,143 +1,171 @@ classdef TwoSidedBarrier < handle - % The log barrier for the domain {lu <= x <= ub}: - % phi(x) = - sum log(x - lb) - sum log(ub - x). - properties (SetAccess = private) - ub % ub - lb % lb - n % Number of variables - center % Some feasible point x - end - - methods - function o = TwoSidedBarrier(lb, ub) - % TwoSidedBarrier(lb, ub) - % Construct a barrier with lower bound lb and upper bound ub. - - o.set(lb, ub); - end - - function set(o, lb, ub) - % o.set(lb, ub) - % Update the bounds lb and ub. - - o.n = length(lb); - assert(all(size(lb) == [o.n, 1]), 'Incompatible Size.'); - assert(all(size(ub) == [o.n, 1]), 'Incompatible Size.'); - assert(all(lb <= ub), 'Infeasible domain.'); - - % Unbounded domain would lead to unbounded domain - - - if (any(lb <= -Inf) || any(ub >= Inf)) - warning('Finite lower and upper bound are required for every constraint. We continue by assuming the set is coordinate-wise bounded by 1e+5.'); - lb = max(lb, -1e+5); - ub = min(ub, 1e+5); - end - - o.lb = lb; - o.ub = ub; - c = (o.ub+o.lb)/2; - o.center = c; - end - - function t = feasible(o, x) - % t = o.feasible(x) - % Output if x is feasible - - t = min(double(o.distance(x))) > 0; - end - - function t = distance(o, x, v) - % t = o.distance(x) - % Output the distance of x with its closest boundary for each coordinate - % Any negative entries implies infeasible - % - % t = o.distance(x, v) - % Output the maximum step from x with direction v for each coordinate - if nargin == 2 - t = min(x-o.lb, o.ub-x); - else - t = ((o.ub - x).*(v>=0) + (o.lb - x).*(v<0))./v; - end - end - - function [g, h, t] = derivatives(o, x) - % [g, h, t] = o.derivatives(x) - % Output the gradient, Hessian and the third derivative of phi(x). - - s1 = 1./(o.ub - x); - s2 = 1./(x - o.lb); - - if nargout >= 1 - g = s1 - s2; - end - - if nargout >= 2 - h = s1 .* s1 + s2 .* s2; - end - - if nargout >= 3 - t = -2*(s1 .* s1 .* s1 - s2 .* s2 .* s2); - end - end - - function [idx, b] = boundary(o, x, blocks) - % [idx, b] = o.boundary(x, blocks) - % Output the boundary value of each block and their cooresponding indices - - c = o.center; - - b = o.ub; - b(x o.lb) & (x < o.ub), o.vdim); + end + + function t = step_size(o, x, v) + % t = o.stepsize(x, v) + % Output the maximum step size from x with direction v. + + max_step = 1e16; % largest step size + if (o.vdim == 2) + max_step = max_step * ones(size(x,1),1); + end + + % check positive direction + posIdx = v > 0; + t1 = min((o.ub(posIdx) - x(posIdx))./v(posIdx), [], o.vdim); + if isempty(t1), t1 = max_step; end + + % check negative direction + negIdx = v < 0; + t2 = min((o.lb(negIdx) - x(negIdx))./v(negIdx), [], o.vdim); + if isempty(t2), t2 = max_step; end + + t = min(min(t1, t2), max_step); + end + + function [A, b] = boundary(o, x) + % [A, b] = o.boundary(x) + % Output the normal at the boundary around x for each barrier. + % Assume: only 1 vector is given + + assert(size(x, 3-o.vdim) == 1); + + c = o.center; + + b = o.ub; + b(x field.length-1 - data_i = extractBetween(data_i, 1, field.length-1); - data_i = data_i{1}; + s = [s, newline, repmat('-', 1, total_length), newline]; + end + + function s = print(o, data) + % s = o.print(item); + % Print out a row of the table with the data + + s = ''; + fields = fieldnames(o.format); + for i = 1:length(fields) + name = fields{i}; + if (isfield(data, name)) + data_i = data.(name); + else + data_i = o.format.(fields{i}).default; + end + field = o.format.(name); + if strcmp(field.type, 'string') && ... + strlength(data_i) > field.length-1 + data_i = extractBetween(data_i, 1, field.length-1); + data_i = data_i{1}; + end + s = strcat(s, sprintf(strcat('%', field.format), data_i), ' '); end - s = [s, sprintf(['%', field.format], data_i), ' ']; - end - - o.output(s); - end - end -end + + s = [s, newline]; + end + end +end \ No newline at end of file diff --git a/test/models b/test/models index e110c00490..4ec76c8398 160000 --- a/test/models +++ b/test/models @@ -1 +1 @@ -Subproject commit e110c0049066b4f07d76bea9f31d364e8a1ab977 +Subproject commit 4ec76c8398e1fb56f1ff67682ea850004ef8f85a diff --git a/tutorials b/tutorials index ead60d4a2c..d87873ff35 160000 --- a/tutorials +++ b/tutorials @@ -1 +1 @@ -Subproject commit ead60d4a2c63f24d702093dd02b7ac868e14babf +Subproject commit d87873ff3559a2bb34e02d61b3933ef238eb55b7 From 92276caad14ab2c297cbd303c9ccda4f4fe381d2 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Sun, 3 Nov 2024 15:21:42 +0000 Subject: [PATCH 41/77] Update testFindRxnsFromMets.m --- .../testExploration/testFindRxnsFromMets.m | 131 ++++++++++-------- 1 file changed, 77 insertions(+), 54 deletions(-) diff --git a/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m b/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m index ffdd3040fd..b5fe58eb42 100644 --- a/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m +++ b/test/verifiedTests/analysis/testExploration/testFindRxnsFromMets.m @@ -1,71 +1,94 @@ -% The COBRAToolbox: testFindRxnsFromGenes.m +% The COBRAToolbox: testFindRxnsFromMets.m % % Purpose: -% - tests that reactions are found when providing a list of genes. -% - tests the correct functionality of findRxnFromGenes function +% - Tests the functionality of findRxnFromMets with all available +% parameters % % Authors: -% - Original file: Stefania Magnusdottir August 2017 -% Samira Ranjbar -November 2023 (revise) - - -global CBTDIR +% - Original file: Thomas Pfau Jan 2018 +% % save the current path currentDir = pwd; % initialize the test -fileDir = fileparts(which('testFindRxnsFromGenes')); +fileDir = fileparts(which('testFindRxnsFromMets')); cd(fileDir); % load model model = getDistributedModel('ecoli_core_model.mat'); -% convert to new style model -model = convertOldStyleModel(model); - -% get reactions for gene list, include gene not in model and nested cell -geneList = {'b0115'; {'b0722'; 'MadeUp'}}; - -% Initiate the test -fprintf(' -- Running testFindRxnsFromGenes ... '); - -[geneRxnsStruct, geneRxnsArray] = findRxnsFromGenes(model, geneList, 0, 1); - -%Check warning message -warningmessage = lastwarn; -assert(strfind(warningmessage,'MadeUp')>0); -assert(isempty(strfind(warningmessage,'b0722'))); -assert(isempty(strfind(warningmessage,'b0115'))); - - -% find gene indeces of genes in model -geneInd = find(ismember(model.genes, {'b0115'; 'b0722'})); - -% manually find reactions associated with gene -rxnInds = []; -for i = 1:length(geneInd) - rxnInds = union(rxnInds, ... - find(~cellfun(@isempty, strfind(model.rules, ['x(', num2str(geneInd(i)), ')'])))); -end - -% check that result array has correct size and rxns -assert(size(geneRxnsArray, 1) == length(rxnInds)) -assert(size(geneRxnsArray, 2) == 6) -assert(isequal(geneRxnsArray(:, 1), model.rxns(rxnInds))) -assert(isequal(geneRxnsArray(:, 6), strcat('gene_', model.genes(geneInd)))) - -% check that result structure has correct size and rxns -for i = 1:length(geneInd) - geneRxns = (geneRxnsStruct.(['gene_', model.genes{geneInd(i)}])); - rxnInds = find(~cellfun(@isempty, strfind(model.rules, ['x(', num2str(geneInd(i)), ')']))); - assert(size(geneRxns, 1) == length(rxnInds)) - assert(size(geneRxns, 2) == 5) - assert(isequal(geneRxns(:, 1), model.rxns(rxnInds))) -end +% Initialize the test +fprintf(' -- Running testFindRxnsFromMets ... \n'); + +% First, find all reactions involved with 3pg +singleTestMet = model.mets{3}; +involvedReacs = {'Biomass_Ecoli_core_w_GAM';'PGK';'PGM'}; +consuming = involvedReacs; +producing = involvedReacs(2:3); +reacs = findRxnsFromMets(model,singleTestMet); +assert(isempty(setxor(involvedReacs,reacs))); +reacs = findRxnsFromMets(model,singleTestMet,'consumersOnly',true); +assert(isempty(setxor(consuming,reacs))); +reacs = findRxnsFromMets(model,singleTestMet,'producersOnly',true); +assert(isempty(setxor(producing,reacs))); + +% now, we change the bounds of PGK to not function in the forward direction +modelChanged = changeRxnBounds(model,'PGK',0,'l'); +modelChanged = changeRxnBounds(modelChanged,'PGM',0,'u'); +reacs = findRxnsFromMets(modelChanged,singleTestMet,'producersOnly',true); +assert(isempty(reacs)); + +% now, test the same with consumers and the PGM reaction, only biomass is +% left. +modelChanged = changeRxnBounds(model,'PGM',0,'l'); +modelChanged = changeRxnBounds(modelChanged,'PGK',0,'u'); +reacs = findRxnsFromMets(modelChanged,singleTestMet,'consumersOnly',true); +assert(isempty(setxor(involvedReacs(1),reacs))); + +% lets test 2 metabolites (2pg and 3pg) +dualTestMet = model.mets(2:3); +involvedReacs = {'Biomass_Ecoli_core_w_GAM';'ENO';'PGM';'PGK'}; +consuming = involvedReacs; +producing = involvedReacs(2:4); +reacs = findRxnsFromMets(model,dualTestMet); +assert(isempty(setxor(involvedReacs,reacs))); +reacs = findRxnsFromMets(model,dualTestMet,'consumersOnly',true); +assert(isempty(setxor(consuming,reacs))); +reacs = findRxnsFromMets(model,dualTestMet,'producersOnly',true); +assert(isempty(setxor(producing,reacs))); + +% test printout. +% build comparison text +res = printRxnFormula(model,'PGM'); +compText = res{1}; % this is sufficient; + +% create diary +diaryFile = 'RxnsFromMetTest'; +diary(diaryFile) +reacs = findRxnsFromMets(model,dualTestMet,'containsAll',true,'printFlag',1); +assert(isempty(setxor({'PGM'},reacs))); +diary off +text = importdata(diaryFile); +assert(~isempty(strfind(strrep(text,'\n',''),compText))); +%cleanup +delete(diaryFile); + + +% test implicit printOut is silent, if no output is created +diary(diaryFile) +[reacs,forms] = findRxnsFromMets(model,dualTestMet,'containsAll',true); +diary off; +text = importdata(diaryFile); +% ITs not found in the output +assert(isempty(strfind(text,compText))); +% but is equal to printRxnFormula +assert(isequal(forms,res)) +%cleanup +delete(diaryFile); + +% Print a success message +fprintf('Done.\n'); % change the directory cd(currentDir) - -% output a success message -fprintf('Done.\n'); From 2f6e0b8139fb8b562eb805eba7f396aceba28c9f Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:37:14 +0000 Subject: [PATCH 42/77] Update codecov.yml --- .github/workflows/codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 217ba2ede4..76987cc28e 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -19,7 +19,7 @@ jobs: with: release: R2022a # Specify the MATLAB version - # Run only the specific test_myfunction.m file from the /tests directory + # Run only the specific test_myfunction.m file from the /tests directory. - name: Run MATLAB tests and generate coverage run: | matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('test/test_myfunction.m')); assertSuccess(results);" From 63f47bcd127289500a47c5077f93ea62ec4a5931 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:05:37 +0000 Subject: [PATCH 43/77] Add files via upload --- .github/README.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 .github/README.md diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000000..c783ccc186 --- /dev/null +++ b/.github/README.md @@ -0,0 +1,214 @@ + +# Code Cov CI - GitHub Actions Workflow + +This repository contains the **Code Cov CI** GitHub Actions workflow, which automates the process of running MATLAB tests and generating code coverage reports using Codecov. The workflow is triggered on pushes and pull requests to the `develop` branch. + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Setup Instructions](#setup-instructions) +- [Workflow Breakdown](#workflow-breakdown) + - [Trigger Configuration](#trigger-configuration) + - [Jobs Definition](#jobs-definition) + - [Steps Breakdown](#steps-breakdown) +- [Codecov Integration](#codecov-integration) +- [Project Structure](#project-structure) +- [Benefits](#benefits) +- [License](#license) + +## Overview + +The **Code Cov CI** workflow automates testing and code coverage reporting for your MATLAB project. It ensures that your code changes are tested and that code coverage metrics are updated automatically. + +## Prerequisites + +- **MATLAB R2022a**: The workflow uses MATLAB R2022a. Ensure your code is compatible with this version. +- **GitHub Repository**: Your project should be hosted in a GitHub repository. +- **Codecov Account**: Sign up for a [Codecov](https://codecov.io/) account to access code coverage reports. +- **Codecov Token**: Obtain a `CODECOV_TOKEN` from Codecov for authentication. + +## Setup Instructions + +1. **Clone the Repository** (if not already): + + ```bash + git clone https://github.com/your-username/your-repository.git + ``` + +2. **Add the Workflow File**: + + - Save the provided workflow YAML file as `.github/workflows/codecov-ci.yml` in your repository. + +3. **Store Codecov Token**: + + - In your GitHub repository, go to **Settings** > **Secrets and variables** > **Actions**. + - Click on **New repository secret**. + - Add `CODECOV_TOKEN` as the name and paste your Codecov token as the value. + +4. **Organize Your Project**: + + - **Source Code**: Place your MATLAB source code in the `src` directory. + - **Tests**: Place your test files in the `test` directory. Ensure `test_myfunction.m` is in this directory. + +5. **Push Changes**: + + ```bash + git add . + git commit -m "Add Code Cov CI workflow" + git push origin develop + ``` + +## Workflow Breakdown + +### Trigger Configuration + +The workflow is triggered on push events and pull requests to the `develop` branch. + +```yaml +on: + push: + branches: [develop] + pull_request: + branches: [develop] +``` + +### Jobs Definition + +The workflow defines a job named `test` that runs on the latest Ubuntu environment. + +```yaml +jobs: + test: + runs-on: ubuntu-latest +``` + +### Steps Breakdown + +1. **Checkout Repository** + + Checks out your repository code so the workflow can access it. + + ```yaml + - uses: actions/checkout@v3 + ``` + +2. **Set Up MATLAB** + + Installs MATLAB R2022a on the runner to execute MATLAB scripts and functions. + + ```yaml + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + with: + release: R2022a + ``` + +3. **Run MATLAB Tests and Generate Coverage** + + Executes the specified MATLAB test and generates a code coverage report in Cobertura XML format. + + ```yaml + - name: Run MATLAB tests and generate coverage + run: | + matlab -batch "import matlab.unittest.TestRunner; \ + import matlab.unittest.plugins.CodeCoveragePlugin; \ + import matlab.unittest.plugins.codecoverage.CoberturaFormat; \ + runner = TestRunner.withTextOutput; \ + runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); \ + results = runner.run(testsuite('test/test_myfunction.m')); \ + assertSuccess(results);" + ``` + +4. **Upload Coverage to Codecov** + + Uploads the generated code coverage report to Codecov for analysis. + + ```yaml + - name: Upload coverage to Codecov + run: | + bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + ``` + +## Codecov Integration + +To visualize your code coverage metrics: + +1. **Log in to Codecov**: Go to [Codecov](https://codecov.io/) and log in with your GitHub account. + +2. **Find Your Repository**: Locate your GitHub repository in Codecov. + +3. **View Coverage Reports**: After the workflow runs, your coverage reports will be available under your repository in Codecov. + +## Project Structure + +Organize your project as follows: + +``` +your-repository/ +├── .github/ +│ └── workflows/ +│ └── codecov-ci.yml +├── src/ +│ └── (Your MATLAB source code) +├── test/ +│ └── test_myfunction.m +├── README.md +└── (Other project files) +``` + +## Benefits + +- **Automated Testing**: Ensures new code changes are tested automatically. +- **Continuous Integration**: Integrates testing and coverage reporting into your development workflow. +- **Code Coverage Insights**: Identifies untested parts of your codebase, helping improve test coverage. +- **Quality Assurance**: Fails the workflow if tests do not pass, maintaining high code quality. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +--- + +For any questions or assistance, feel free to open an issue or reach out to the maintainers. + +# Workflow File: `.github/workflows/codecov-ci.yml` + +```yaml +name: Code Cov CI + +on: + push: + branches: [develop] # Trigger workflow on push to develop + pull_request: + branches: [develop] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + # Set up MATLAB + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + with: + release: R2022a # Specify the MATLAB version + + # Run only the specific test_myfunction.m file from the /tests directory + - name: Run MATLAB tests and generate coverage + run: | + matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('test/test_myfunction.m')); assertSuccess(results);" + + # Upload coverage report to Codecov + - name: Upload coverage to Codecov + run: | + bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +``` + +*Note: Replace `your-username` and `your-repository` with your actual GitHub username and repository name in the URLs and commands.* From afa350be55b9f7fb630186e5a6f45cca69dc7dbf Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:11:07 +0000 Subject: [PATCH 44/77] Update and rename .github/README.md to testAll-CodeCov-README.md --- .../README.md => testAll-CodeCov-README.md | 83 +++---------------- 1 file changed, 10 insertions(+), 73 deletions(-) rename .github/README.md => testAll-CodeCov-README.md (52%) diff --git a/.github/README.md b/testAll-CodeCov-README.md similarity index 52% rename from .github/README.md rename to testAll-CodeCov-README.md index c783ccc186..926b5fd146 100644 --- a/.github/README.md +++ b/testAll-CodeCov-README.md @@ -12,19 +12,17 @@ This repository contains the **Code Cov CI** GitHub Actions workflow, which auto - [Trigger Configuration](#trigger-configuration) - [Jobs Definition](#jobs-definition) - [Steps Breakdown](#steps-breakdown) -- [Codecov Integration](#codecov-integration) - [Project Structure](#project-structure) - [Benefits](#benefits) - [License](#license) ## Overview -The **Code Cov CI** workflow automates testing and code coverage reporting for your MATLAB project. It ensures that your code changes are tested and that code coverage metrics are updated automatically. +The **Code Cov CI** workflow automates testing and code coverage. It ensures that code changes are tested and that code coverage metrics are updated automatically. ## Prerequisites - **MATLAB R2022a**: The workflow uses MATLAB R2022a. Ensure your code is compatible with this version. -- **GitHub Repository**: Your project should be hosted in a GitHub repository. - **Codecov Account**: Sign up for a [Codecov](https://codecov.io/) account to access code coverage reports. - **Codecov Token**: Obtain a `CODECOV_TOKEN` from Codecov for authentication. @@ -38,18 +36,18 @@ The **Code Cov CI** workflow automates testing and code coverage reporting for y 2. **Add the Workflow File**: - - Save the provided workflow YAML file as `.github/workflows/codecov-ci.yml` in your repository. + - Save the provided workflow YAML file as `.github/workflows/codecov.yml` in your repository. 3. **Store Codecov Token**: - - In your GitHub repository, go to **Settings** > **Secrets and variables** > **Actions**. + - In the repository, go to **Settings** > **Secrets and variables** > **Actions**. - Click on **New repository secret**. - Add `CODECOV_TOKEN` as the name and paste your Codecov token as the value. 4. **Organize Your Project**: - - **Source Code**: Place your MATLAB source code in the `src` directory. - - **Tests**: Place your test files in the `test` directory. Ensure `test_myfunction.m` is in this directory. + - **Source Code**: MATLAB source code in the `src` directory, which it aready is. + - **Tests**: Place test files in the `test` directory. Ensure `testAll.m` is in this directory. 5. **Push Changes**: @@ -116,7 +114,7 @@ jobs: import matlab.unittest.plugins.codecoverage.CoberturaFormat; \ runner = TestRunner.withTextOutput; \ runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); \ - results = runner.run(testsuite('test/test_myfunction.m')); \ + results = runner.run(testsuite('test/testAll.m')); \ assertSuccess(results);" ``` @@ -132,15 +130,6 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} ``` -## Codecov Integration - -To visualize your code coverage metrics: - -1. **Log in to Codecov**: Go to [Codecov](https://codecov.io/) and log in with your GitHub account. - -2. **Find Your Repository**: Locate your GitHub repository in Codecov. - -3. **View Coverage Reports**: After the workflow runs, your coverage reports will be available under your repository in Codecov. ## Project Structure @@ -150,65 +139,13 @@ Organize your project as follows: your-repository/ ├── .github/ │ └── workflows/ -│ └── codecov-ci.yml +│ └── codecov.yml ├── src/ -│ └── (Your MATLAB source code) +│ └── (MATLAB source code) ├── test/ -│ └── test_myfunction.m -├── README.md +│ └── testAll.m +├ └── (Other project files) ``` -## Benefits - -- **Automated Testing**: Ensures new code changes are tested automatically. -- **Continuous Integration**: Integrates testing and coverage reporting into your development workflow. -- **Code Coverage Insights**: Identifies untested parts of your codebase, helping improve test coverage. -- **Quality Assurance**: Fails the workflow if tests do not pass, maintaining high code quality. - -## License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - ---- - -For any questions or assistance, feel free to open an issue or reach out to the maintainers. - -# Workflow File: `.github/workflows/codecov-ci.yml` - -```yaml -name: Code Cov CI - -on: - push: - branches: [develop] # Trigger workflow on push to develop - pull_request: - branches: [develop] - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - # Set up MATLAB - - name: Set up MATLAB - uses: matlab-actions/setup-matlab@v1 - with: - release: R2022a # Specify the MATLAB version - - # Run only the specific test_myfunction.m file from the /tests directory - - name: Run MATLAB tests and generate coverage - run: | - matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('test/test_myfunction.m')); assertSuccess(results);" - - # Upload coverage report to Codecov - - name: Upload coverage to Codecov - run: | - bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} -``` -*Note: Replace `your-username` and `your-repository` with your actual GitHub username and repository name in the URLs and commands.* From 49e7ee0aecbace9d80bc0ed9d98ca5d4f60c538f Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:11:23 +0000 Subject: [PATCH 45/77] Update testAll-CodeCov-README.md --- testAll-CodeCov-README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testAll-CodeCov-README.md b/testAll-CodeCov-README.md index 926b5fd146..3cb868c9c4 100644 --- a/testAll-CodeCov-README.md +++ b/testAll-CodeCov-README.md @@ -1,5 +1,5 @@ -# Code Cov CI - GitHub Actions Workflow +# TestAll and Code Cov CI - GitHub Actions Workflow This repository contains the **Code Cov CI** GitHub Actions workflow, which automates the process of running MATLAB tests and generating code coverage reports using Codecov. The workflow is triggered on pushes and pull requests to the `develop` branch. From 256caabe47b402223a687d6289a96e5192e5de2c Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:14:10 +0000 Subject: [PATCH 46/77] Update testAll-CodeCov-README.md --- testAll-CodeCov-README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testAll-CodeCov-README.md b/testAll-CodeCov-README.md index 3cb868c9c4..8ca53bc1de 100644 --- a/testAll-CodeCov-README.md +++ b/testAll-CodeCov-README.md @@ -31,7 +31,7 @@ The **Code Cov CI** workflow automates testing and code coverage. It ensures tha 1. **Clone the Repository** (if not already): ```bash - git clone https://github.com/your-username/your-repository.git + git clone https://github.com/opencobra/cobratoolbox.git ``` 2. **Add the Workflow File**: From 9aaa00ea19c174dd1fb51c3f45068ae7b78f1bd1 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:14:46 +0000 Subject: [PATCH 47/77] Rename testAll-CodeCov-README.md to .github/workflows/testAll-CodeCov-README.md --- .../workflows/testAll-CodeCov-README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename testAll-CodeCov-README.md => .github/workflows/testAll-CodeCov-README.md (100%) diff --git a/testAll-CodeCov-README.md b/.github/workflows/testAll-CodeCov-README.md similarity index 100% rename from testAll-CodeCov-README.md rename to .github/workflows/testAll-CodeCov-README.md From 4788422f43cce63d3561d651d442ffd954337d64 Mon Sep 17 00:00:00 2001 From: Farid Zare Date: Mon, 4 Nov 2024 14:45:07 +0000 Subject: [PATCH 48/77] Update testAll.m --- test/testAll.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/testAll.m b/test/testAll.m index 5c5f67a004..089d046139 100644 --- a/test/testAll.m +++ b/test/testAll.m @@ -14,10 +14,12 @@ fprintf(' | \n\n'); % request explicitly from the user to launch test suite locally -if contains(getenv('HOME'), 'vmhadmin') || contains(getenv('HOME'), 'jenkins') +% if contains(getenv('HOME'), 'vmhadmin') || contains(getenv('HOME'), 'jenkins') +if contains(getenv('HOME'), 'cobratoolbox') % Running in CI environment - fprintf('Running test in Jenkins/CI environment\n'); - +% fprintf('Running test in Jenkins/CI environment\n'); + fprintf('Running test in cobratoolbox/CI environment\n'); + % on the CI, always reset the path to make absolutely sure, that we test % the current version restoredefaultpath; From 0fb422eac91f04c0728c19fd9928c2211bb8f9f5 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:46:39 +0000 Subject: [PATCH 49/77] Update runTestsAndGenerateReport.m --- runTestsAndGenerateReport.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runTestsAndGenerateReport.m b/runTestsAndGenerateReport.m index 62b0d9b5c5..de08fe1474 100644 --- a/runTestsAndGenerateReport.m +++ b/runTestsAndGenerateReport.m @@ -1,6 +1,6 @@ % Run your tests -testResults = runtests('./test/testAll_ghActions.m'); - +% testResults = runtests('./test/testAll_ghActions.m'); +testResults = runtests('./test/testAll.m'); % Open a file for writing fid = fopen('test_results.txt', 'w'); From 65fad09ec7592478c7dbf7fc3316905be11e2e63 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:21:58 +0000 Subject: [PATCH 50/77] Update codecov.yml --- .github/workflows/codecov.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 76987cc28e..d41e169ae8 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -18,12 +18,17 @@ jobs: uses: matlab-actions/setup-matlab@v1 with: release: R2022a # Specify the MATLAB version + - # Run only the specific test_myfunction.m file from the /tests directory. - - name: Run MATLAB tests and generate coverage + # Run MATLAB tests with MOcov to generate coverage + - name: Run MATLAB tests and generate MOcov coverage run: | - matlab -batch "import matlab.unittest.TestRunner; import matlab.unittest.plugins.CodeCoveragePlugin; import matlab.unittest.plugins.codecoverage.CoberturaFormat; runner = TestRunner.withTextOutput; runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); results = runner.run(testsuite('test/test_myfunction.m')); assertSuccess(results);" - + matlab -batch " + addpath('/opt/MOcov/MOcov'); % Add MOcov to MATLAB path + test_suite = testsuite('test/test_myfunction.m'); + cov_data = mocov('-cover', 'src', '-tests', test_suite, '-quiet', '-cover_xml_file', 'coverage.xml'); + " + # Upload coverage report to Codecov - name: Upload coverage to Codecov run: | From 753ab8e5a81cd7d5a4100b355f264a0186d7e29d Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:22:43 +0000 Subject: [PATCH 51/77] Update codecov.yml --- codecov.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index cbfea8638d..e7e3922bc7 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,6 +1,20 @@ +# codecov.yml + +# Comment settings +comment: + layout: "reach, diff, flags, files" + behavior: default # Shows the comment only on the first push of a pull request + require_changes: true # Only comment if there are coverage changes + +# Coverage status checks coverage: status: project: default: - threshold: 15 - patch: off + target: auto # Automatically adjust coverage goal + threshold: 1% # Fail PRs that reduce coverage by more than 1% + patch: + default: + target: auto + threshold: 1% + From 1b06d4e2f44110e073b5991eee41d312802454d5 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:27:21 +0000 Subject: [PATCH 52/77] Update codecov.yml --- .github/workflows/codecov.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index d41e169ae8..a9f17dfddc 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -18,7 +18,14 @@ jobs: uses: matlab-actions/setup-matlab@v1 with: release: R2022a # Specify the MATLAB version - + + # Install MOcov + - name: Install MOcov + run: | + # Clone MOcov repository to /opt/MOcov + sudo git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov + # Adjust permissions if necessary + sudo chmod -R 755 /opt/MOcov # Run MATLAB tests with MOcov to generate coverage - name: Run MATLAB tests and generate MOcov coverage From 832ea3f6b43b26cedbad2fbf282b6aebc2448a2a Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:32:55 +0000 Subject: [PATCH 53/77] Update codecov.yml --- .github/workflows/codecov.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index a9f17dfddc..327c3994f9 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,14 +27,10 @@ jobs: # Adjust permissions if necessary sudo chmod -R 755 /opt/MOcov - # Run MATLAB tests with MOcov to generate coverage - name: Run MATLAB tests and generate MOcov coverage run: | - matlab -batch " - addpath('/opt/MOcov/MOcov'); % Add MOcov to MATLAB path - test_suite = testsuite('test/test_myfunction.m'); - cov_data = mocov('-cover', 'src', '-tests', test_suite, '-quiet', '-cover_xml_file', 'coverage.xml'); - " + matlab -batch "addpath('/opt/MOcov/MOcov'); test_suite = testsuite('test/test_myfunction.m'); cov_data = mocov('-cover', 'src', '-tests', test_suite, '-quiet', '-cover_xml_file', 'coverage.xml');" + # Upload coverage report to Codecov - name: Upload coverage to Codecov From 4c4a2b51099d5665e65d3defd3406ecc147b52d9 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:38:59 +0000 Subject: [PATCH 54/77] Update codecov.yml --- .github/workflows/codecov.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 327c3994f9..d7618837ea 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -2,35 +2,33 @@ name: Code Cov CI on: push: - branches: [develop] # Trigger workflow on push to develop + branches: [develop] pull_request: branches: [develop] jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-latest # Replace with 'self-hosted' if using your own runner steps: - uses: actions/checkout@v3 - + # Set up MATLAB - name: Set up MATLAB uses: matlab-actions/setup-matlab@v1 with: - release: R2022a # Specify the MATLAB version + release: R2022a - # Install MOcov - - name: Install MOcov + # Install MOxUnit and MOcov + - name: Install MOxUnit and MOcov run: | - # Clone MOcov repository to /opt/MOcov - sudo git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov - # Adjust permissions if necessary - sudo chmod -R 755 /opt/MOcov + git clone https://github.com/MOxUnit/MOxUnit.git /opt/MOxUnit + git clone https://github.com/MOcov/MOcov.git /opt/MOcov + # Run MATLAB tests with MOxUnit and generate coverage - name: Run MATLAB tests and generate MOcov coverage run: | - matlab -batch "addpath('/opt/MOcov/MOcov'); test_suite = testsuite('test/test_myfunction.m'); cov_data = mocov('-cover', 'src', '-tests', test_suite, '-quiet', '-cover_xml_file', 'coverage.xml');" - + matlab -batch "addpath('/opt/MOxUnit/MOxUnit'); addpath('/opt/MOcov/MOcov'); moxunit_runtests('test/test_myfunction.m', '-verbose', '-with_coverage', '-cover', 'src', '-cover_xml_file', 'coverage.xml');" # Upload coverage report to Codecov - name: Upload coverage to Codecov From 61a935f84f0ae6ac0ddce30d01e9c34db3e0449c Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:45:01 +0000 Subject: [PATCH 55/77] Update codecov.yml --- .github/workflows/codecov.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index d7618837ea..9d31b19c0b 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -2,7 +2,7 @@ name: Code Cov CI on: push: - branches: [develop] + branches: [develop] # Trigger workflow on push to develop pull_request: branches: [develop] @@ -19,16 +19,22 @@ jobs: with: release: R2022a - # Install MOxUnit and MOcov - - name: Install MOxUnit and MOcov + # Install MOcov + - name: Install MOcov run: | - git clone https://github.com/MOxUnit/MOxUnit.git /opt/MOxUnit git clone https://github.com/MOcov/MOcov.git /opt/MOcov + sudo chmod -R 755 /opt/MOcov - # Run MATLAB tests with MOxUnit and generate coverage + # Run tests and generate coverage with MOcov - name: Run MATLAB tests and generate MOcov coverage run: | - matlab -batch "addpath('/opt/MOxUnit/MOxUnit'); addpath('/opt/MOcov/MOcov'); moxunit_runtests('test/test_myfunction.m', '-verbose', '-with_coverage', '-cover', 'src', '-cover_xml_file', 'coverage.xml');" + matlab -batch " + addpath('/opt/MOcov'); + mocov('-cover', 'src', ... + '-expression', 'result = runtests("test"); assert(all([result.Passed]), "Some tests failed.");', ... + '-cover_xml_file', 'coverage.xml', ... + '-method', 'file'); + " # Upload coverage report to Codecov - name: Upload coverage to Codecov From 0f74c1d825c7bae8fc870db75aa5358fc688e33a Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:50:51 +0000 Subject: [PATCH 56/77] Update codecov.yml --- .github/workflows/codecov.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 9d31b19c0b..1540b2f2ab 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -2,7 +2,7 @@ name: Code Cov CI on: push: - branches: [develop] # Trigger workflow on push to develop + branches: [develop] pull_request: branches: [develop] @@ -28,13 +28,7 @@ jobs: # Run tests and generate coverage with MOcov - name: Run MATLAB tests and generate MOcov coverage run: | - matlab -batch " - addpath('/opt/MOcov'); - mocov('-cover', 'src', ... - '-expression', 'result = runtests("test"); assert(all([result.Passed]), "Some tests failed.");', ... - '-cover_xml_file', 'coverage.xml', ... - '-method', 'file'); - " + matlab -batch "addpath('/opt/MOcov'); mocov('-cover', 'src', '-expression', 'result = runtests(\"test\"); assert(all([result.Passed]), \"Some tests failed.\");', '-cover_xml_file', 'coverage.xml', '-method', 'file');" # Upload coverage report to Codecov - name: Upload coverage to Codecov From b33b46ba5e8666572dbe5c357bcc6096aa0f1b5d Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:56:20 +0000 Subject: [PATCH 57/77] Update codecov.yml --- .github/workflows/codecov.yml | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 1540b2f2ab..6f3d9c41a8 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -1,4 +1,4 @@ -name: Code Cov CI +name: Code Coverage on: push: @@ -8,31 +8,37 @@ on: jobs: test: - runs-on: ubuntu-latest # Replace with 'self-hosted' if using your own runner + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # Set up MATLAB - name: Set up MATLAB uses: matlab-actions/setup-matlab@v1 with: release: R2022a - # Install MOcov - name: Install MOcov run: | git clone https://github.com/MOcov/MOcov.git /opt/MOcov sudo chmod -R 755 /opt/MOcov - # Run tests and generate coverage with MOcov - - name: Run MATLAB tests and generate MOcov coverage + - name: Run MATLAB tests with coverage run: | - matlab -batch "addpath('/opt/MOcov'); mocov('-cover', 'src', '-expression', 'result = runtests(\"test\"); assert(all([result.Passed]), \"Some tests failed.\");', '-cover_xml_file', 'coverage.xml', '-method', 'file');" + matlab -batch " + addpath(genpath('/opt/MOcov')); + addpath(genpath('test')); + addpath(genpath('src')); + mocov('start'); + results = runtests('test_myfunction.m'); + assert(all([results.Passed]), 'Some tests failed'); + mocov('stop'); + mocov('-cover', 'src', '-cover_xml_file', 'coverage.xml'); + exit;" - # Upload coverage report to Codecov - name: Upload coverage to Codecov - run: | - bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: codecov/codecov-action@v3 + with: + files: ./coverage.xml + flags: matlab + token: ${{ secrets.CODECOV_TOKEN }} From 0aca2243f8fc004e01ebcb1cac197862e7bad223 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:58:06 +0000 Subject: [PATCH 58/77] Update codecov.yml --- .github/workflows/codecov.yml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 6f3d9c41a8..b6bf80e4dc 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -24,17 +24,22 @@ jobs: sudo chmod -R 755 /opt/MOcov - name: Run MATLAB tests with coverage - run: | + run: > matlab -batch " - addpath(genpath('/opt/MOcov')); - addpath(genpath('test')); - addpath(genpath('src')); - mocov('start'); - results = runtests('test_myfunction.m'); - assert(all([results.Passed]), 'Some tests failed'); - mocov('stop'); - mocov('-cover', 'src', '-cover_xml_file', 'coverage.xml'); - exit;" + try + addpath(genpath('/opt/MOcov')); + addpath(genpath('test')); + addpath(genpath('src')); + mocov('start'); + results = runtests('test_myfunction.m'); + assert(all([results.Passed]), 'Some tests failed'); + mocov('stop'); + mocov('-cover', 'src', '-cover_xml_file', 'coverage.xml'); + exit(0); + catch e + disp(getReport(e)); + exit(1); + end" - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 From 66c7974cba28f754b53f3fea3e1966e177e9f803 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:01:34 +0000 Subject: [PATCH 59/77] Update codecov.yml --- .github/workflows/codecov.yml | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index b6bf80e4dc..ffa54ca475 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -20,26 +20,28 @@ jobs: - name: Install MOcov run: | - git clone https://github.com/MOcov/MOcov.git /opt/MOcov + git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov + ls -la /opt/MOcov sudo chmod -R 755 /opt/MOcov - - name: Run MATLAB tests with coverage - run: > - matlab -batch " + - name: Create and run MATLAB script + run: | + echo 'addpath(genpath('\''/opt/MOcov'\'')); + addpath(genpath(''test'')); + addpath(genpath(''src'')); + mocov(''start''); try - addpath(genpath('/opt/MOcov')); - addpath(genpath('test')); - addpath(genpath('src')); - mocov('start'); - results = runtests('test_myfunction.m'); - assert(all([results.Passed]), 'Some tests failed'); - mocov('stop'); - mocov('-cover', 'src', '-cover_xml_file', 'coverage.xml'); - exit(0); + results = runtests(''test_myfunction.m''); + assert(all([results.Passed]), ''Some tests failed''); + mocov(''stop''); + mocov(''-cover'', ''src'', ''-cover_xml_file'', ''coverage.xml''); + exit(0); catch e - disp(getReport(e)); - exit(1); - end" + disp(getReport(e)); + exit(1); + end' > run_tests.m + + matlab -batch "run('run_tests.m')" - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 From f717b8e687bc53a265e01be19c75f27a9f655390 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:05:19 +0000 Subject: [PATCH 60/77] Update codecov.yml --- .github/workflows/codecov.yml | 36 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index ffa54ca475..fabd1c123e 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -21,27 +21,37 @@ jobs: - name: Install MOcov run: | git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov - ls -la /opt/MOcov sudo chmod -R 755 /opt/MOcov - - name: Create and run MATLAB script + - name: Create MATLAB script run: | - echo 'addpath(genpath('\''/opt/MOcov'\'')); - addpath(genpath(''test'')); - addpath(genpath(''src'')); - mocov(''start''); + cat << 'EOF' > run_tests.m + % Add MOcov to path + addpath(genpath('/opt/MOcov')); + + % Add test directories + addpath('tests'); + + % Start coverage + mocov('start'); + try - results = runtests(''test_myfunction.m''); - assert(all([results.Passed]), ''Some tests failed''); - mocov(''stop''); - mocov(''-cover'', ''src'', ''-cover_xml_file'', ''coverage.xml''); + % Run the test + results = runtests('tests/test_myfunction.m'); + assert(all([results.Passed]), 'Some tests failed'); + + % Stop coverage and generate report + mocov('stop'); + mocov('-cover', pwd, '-cover_xml_file', 'coverage.xml'); exit(0); catch e disp(getReport(e)); exit(1); - end' > run_tests.m - - matlab -batch "run('run_tests.m')" + end + EOF + + - name: Run MATLAB tests + run: matlab -batch "run('run_tests.m')" - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 From 3269f2147f0213d441711600cd94a08532d60364 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:09:53 +0000 Subject: [PATCH 61/77] Create run_coverage_tests.m --- run_coverage_tests.m | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 run_coverage_tests.m diff --git a/run_coverage_tests.m b/run_coverage_tests.m new file mode 100644 index 0000000000..7971045bf6 --- /dev/null +++ b/run_coverage_tests.m @@ -0,0 +1,35 @@ +function run_coverage_tests + % Add MOcov to path + addpath(genpath('/opt/MOcov')); + + % Get the current directory + current_dir = pwd; + + try + % Configure MOcov + cover_method = '-cover'; + covered_dir = current_dir; + report_file = fullfile(current_dir, 'coverage.xml'); + + % Run tests and generate coverage + test_suite = testsuite('tests/test_myfunction.m'); + results = run(test_suite); + + % Check if all tests passed + num_failed = nnz([results.Failed]); + if num_failed > 0 + error('Some tests failed'); + end + + % Generate coverage report + mocov(cover_method, covered_dir, '-cover_xml_file', report_file); + + % Exit with success + exit(0); + catch e + % Display error and exit with failure + disp('Error running tests:'); + disp(getReport(e)); + exit(1); + end +end From 6ed0899dbbd6993998e2ff4ac3310e2018ca6cb9 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:10:41 +0000 Subject: [PATCH 62/77] Update codecov.yml --- .github/workflows/codecov.yml | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index fabd1c123e..c097d5633b 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -23,35 +23,8 @@ jobs: git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov sudo chmod -R 755 /opt/MOcov - - name: Create MATLAB script - run: | - cat << 'EOF' > run_tests.m - % Add MOcov to path - addpath(genpath('/opt/MOcov')); - - % Add test directories - addpath('tests'); - - % Start coverage - mocov('start'); - - try - % Run the test - results = runtests('tests/test_myfunction.m'); - assert(all([results.Passed]), 'Some tests failed'); - - % Stop coverage and generate report - mocov('stop'); - mocov('-cover', pwd, '-cover_xml_file', 'coverage.xml'); - exit(0); - catch e - disp(getReport(e)); - exit(1); - end - EOF - - name: Run MATLAB tests - run: matlab -batch "run('run_tests.m')" + run: matlab -batch "run('run_coverage_tests.m')" - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 From 7d14232314d3402cd9d5e4c2b10cc696c065a5eb Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:16:18 +0000 Subject: [PATCH 63/77] Update test_myfunction.m --- test/test_myfunction.m | 74 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/test/test_myfunction.m b/test/test_myfunction.m index 602f106d1b..63002f6686 100644 --- a/test/test_myfunction.m +++ b/test/test_myfunction.m @@ -1,16 +1,78 @@ classdef test_myfunction < matlab.unittest.TestCase - methods(Test) - function testSimple(testCase) - % Dummy test for the function myfunction - result = myfunction(3); % Call the function defined below + % Test class for myfunction + % This test suite demonstrates various aspects of the function's behavior + + properties + % Define any test properties here + TestPrecision = 1e-10; + end + + methods (Test) + function testPositiveInteger(testCase) + % Test with a positive integer + result = myfunction(3); expected = 9; - testCase.verifyEqual(result, expected); + testCase.verifyEqual(result, expected, ... + 'Failed to square positive integer correctly') + end + + function testNegativeInteger(testCase) + % Test with a negative integer + result = myfunction(-4); + expected = 16; + testCase.verifyEqual(result, expected, ... + 'Failed to square negative integer correctly') + end + + function testZero(testCase) + % Test with zero + result = myfunction(0); + expected = 0; + testCase.verifyEqual(result, expected, ... + 'Failed to handle zero input correctly') + end + + function testDecimal(testCase) + % Test with decimal number + result = myfunction(1.5); + expected = 2.25; + testCase.verifyEqual(result, expected, ... + 'AbsTol', testCase.TestPrecision, ... + 'Failed to square decimal number correctly') + end + + function testLargeNumber(testCase) + % Test with a large number + result = myfunction(1e3); + expected = 1e6; + testCase.verifyEqual(result, expected, ... + 'Failed to handle large numbers correctly') + end + end + + methods (TestClassSetup) + function setupPath(testCase) + % Add the directory containing myfunction to the path + currentDir = fileparts(mfilename('fullpath')); + addpath(currentDir); end end end % The function to be tested function y = myfunction(x) - % Simple function that squares the input + % MYFUNCTION Squares the input value + % y = MYFUNCTION(x) returns the square of x + % + % Inputs: + % x - A numeric value + % + % Outputs: + % y - The square of the input value + % + % Example: + % y = myfunction(3) + % y = 9 + y = x^2; end From 3bb9cc810be1d1096c97a920828e7b74f97ac74a Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:17:02 +0000 Subject: [PATCH 64/77] Update run_coverage_tests.m --- run_coverage_tests.m | 50 ++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index 7971045bf6..a341e724ed 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -6,23 +6,41 @@ current_dir = pwd; try - % Configure MOcov - cover_method = '-cover'; - covered_dir = current_dir; - report_file = fullfile(current_dir, 'coverage.xml'); - - % Run tests and generate coverage - test_suite = testsuite('tests/test_myfunction.m'); - results = run(test_suite); - - % Check if all tests passed - num_failed = nnz([results.Failed]); - if num_failed > 0 - error('Some tests failed'); - end + % Import necessary components + import matlab.unittest.TestRunner; + import matlab.unittest.TestSuite; + import matlab.unittest.plugins.TestReportPlugin; + import matlab.unittest.plugins.CodeCoveragePlugin; + + % Create test suite from the test file + suite = TestSuite.fromFile('tests/test_myfunction.m'); + + % Create a runner + runner = TestRunner.withTextOutput('Verbosity', 3); + + % Add the coverage plugin + coveragePlugin = CodeCoveragePlugin.forFolder(current_dir, ... + 'IncludingSubfolders', true, ... + 'Producing', matlab.unittest.plugins.codecoverage.CoverageReport('coverage')); + runner.addPlugin(coveragePlugin); - % Generate coverage report - mocov(cover_method, covered_dir, '-cover_xml_file', report_file); + % Run the tests + results = runner.run(suite); + + % Display summary + disp('Test Summary:'); + disp(['Number of tests: ' num2str(numel(results))]); + disp(['Passed: ' num2str(nnz([results.Passed]))]); + disp(['Failed: ' num2str(nnz([results.Failed]))]); + disp(['Duration: ' num2str(sum([results.Duration])) ' seconds']); + + % Generate MOcov coverage report + mocov('-cover', current_dir, '-cover_xml_file', 'coverage.xml'); + + % Check if any tests failed + if any([results.Failed]) + error('Some tests failed. Check the test report for details.'); + end % Exit with success exit(0); From d85b734f28b9c6b29e976b4c4024816604979cc6 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:19:55 +0000 Subject: [PATCH 65/77] Update run_coverage_tests.m --- run_coverage_tests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index a341e724ed..ff66febbcf 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -13,7 +13,7 @@ import matlab.unittest.plugins.CodeCoveragePlugin; % Create test suite from the test file - suite = TestSuite.fromFile('tests/test_myfunction.m'); + suite = TestSuite.fromFile('test/test_myfunction.m'); % Create a runner runner = TestRunner.withTextOutput('Verbosity', 3); From 9b23530b88a0e1568e75fe61cd9e3b87ae555e18 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:22:53 +0000 Subject: [PATCH 66/77] Update run_coverage_tests.m --- run_coverage_tests.m | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index ff66febbcf..5d3188db98 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -6,35 +6,27 @@ current_dir = pwd; try - % Import necessary components - import matlab.unittest.TestRunner; - import matlab.unittest.TestSuite; - import matlab.unittest.plugins.TestReportPlugin; - import matlab.unittest.plugins.CodeCoveragePlugin; - % Create test suite from the test file - suite = TestSuite.fromFile('test/test_myfunction.m'); - - % Create a runner - runner = TestRunner.withTextOutput('Verbosity', 3); + suite = matlab.unittest.TestSuite.fromFile('test/test_myfunction.m'); - % Add the coverage plugin - coveragePlugin = CodeCoveragePlugin.forFolder(current_dir, ... - 'IncludingSubfolders', true, ... - 'Producing', matlab.unittest.plugins.codecoverage.CoverageReport('coverage')); - runner.addPlugin(coveragePlugin); + % Create a runner with detailed output + runner = matlab.unittest.TestRunner.withTextOutput('Verbosity', 3); % Run the tests results = runner.run(suite); % Display summary + disp('=========================================='); disp('Test Summary:'); + disp('=========================================='); disp(['Number of tests: ' num2str(numel(results))]); disp(['Passed: ' num2str(nnz([results.Passed]))]); disp(['Failed: ' num2str(nnz([results.Failed]))]); disp(['Duration: ' num2str(sum([results.Duration])) ' seconds']); + disp('=========================================='); % Generate MOcov coverage report + disp('Generating coverage report...'); mocov('-cover', current_dir, '-cover_xml_file', 'coverage.xml'); % Check if any tests failed @@ -42,7 +34,7 @@ error('Some tests failed. Check the test report for details.'); end - % Exit with success + disp('Testing completed successfully.'); exit(0); catch e % Display error and exit with failure From 0055613f5353013a665f604472864c6e4f3b37cf Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:25:42 +0000 Subject: [PATCH 67/77] Update run_coverage_tests.m --- run_coverage_tests.m | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index 5d3188db98..d24d9cba2f 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -2,42 +2,18 @@ % Add MOcov to path addpath(genpath('/opt/MOcov')); - % Get the current directory - current_dir = pwd; - try - % Create test suite from the test file - suite = matlab.unittest.TestSuite.fromFile('test/test_myfunction.m'); - - % Create a runner with detailed output - runner = matlab.unittest.TestRunner.withTextOutput('Verbosity', 3); - - % Run the tests - results = runner.run(suite); + % Run tests directly + disp('Running tests...'); + test_results = test_myfunction; - % Display summary - disp('=========================================='); - disp('Test Summary:'); - disp('=========================================='); - disp(['Number of tests: ' num2str(numel(results))]); - disp(['Passed: ' num2str(nnz([results.Passed]))]); - disp(['Failed: ' num2str(nnz([results.Failed]))]); - disp(['Duration: ' num2str(sum([results.Duration])) ' seconds']); - disp('=========================================='); - - % Generate MOcov coverage report + % Generate coverage report disp('Generating coverage report...'); - mocov('-cover', current_dir, '-cover_xml_file', 'coverage.xml'); - - % Check if any tests failed - if any([results.Failed]) - error('Some tests failed. Check the test report for details.'); - end + mocov('-cover', pwd, '-cover_xml_file', 'coverage.xml'); disp('Testing completed successfully.'); exit(0); catch e - % Display error and exit with failure disp('Error running tests:'); disp(getReport(e)); exit(1); From a8305360f4528e9c94fa041dc62c86304f694f27 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:29:05 +0000 Subject: [PATCH 68/77] Update run_coverage_tests.m --- run_coverage_tests.m | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index d24d9cba2f..3ea4acca04 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -3,15 +3,25 @@ addpath(genpath('/opt/MOcov')); try - % Run tests directly - disp('Running tests...'); - test_results = test_myfunction; + % Run tests and capture results + disp('Running tests with coverage...'); - % Generate coverage report - disp('Generating coverage report...'); - mocov('-cover', pwd, '-cover_xml_file', 'coverage.xml'); + % Create the expression to run tests + test_expression = 'results = runtests("tests/test_myfunction.m"); passed = all([results.Passed]);'; + + % Run MOcov with the test expression + mocov('-cover', pwd, ... + '-cover_xml_file', 'coverage.xml', ... + '-expression', test_expression); + + % Load and display results + if ~passed + error('Some tests failed. Check the test results for details.'); + end + + disp('All tests passed successfully!'); + disp(['Number of passed tests: ' num2str(sum([results.Passed]))]); - disp('Testing completed successfully.'); exit(0); catch e disp('Error running tests:'); From b62671cc3bb564fbba3f88ce71c92e6554c36201 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:32:10 +0000 Subject: [PATCH 69/77] Update run_coverage_tests.m --- run_coverage_tests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index 3ea4acca04..139351d085 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -7,7 +7,7 @@ disp('Running tests with coverage...'); % Create the expression to run tests - test_expression = 'results = runtests("tests/test_myfunction.m"); passed = all([results.Passed]);'; + test_expression = 'results == runtests("tests/test_myfunction.m"); passed == all([results.Passed]);'; % Run MOcov with the test expression mocov('-cover', pwd, ... From b9308395b70bb2ddd66bc7b7b75baa4048743019 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:37:46 +0000 Subject: [PATCH 70/77] Update run_coverage_tests.m --- run_coverage_tests.m | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index 139351d085..4fdc4dee78 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -1,4 +1,4 @@ -function run_coverage_tests +function run_coverage_tests() % Add MOcov to path addpath(genpath('/opt/MOcov')); @@ -6,15 +6,20 @@ % Run tests and capture results disp('Running tests with coverage...'); - % Create the expression to run tests - test_expression = 'results == runtests("tests/test_myfunction.m"); passed == all([results.Passed]);'; + % Create the expression to run tests with proper variable assignment + test_expression = ['results = runtests(''test/test_myfunction.m'');', ... + 'passed = all([results.Passed]);']; % Run MOcov with the test expression - mocov('-cover', pwd, ... + mocov('-cover', '.', ... % Use '.' instead of pwd for current directory '-cover_xml_file', 'coverage.xml', ... '-expression', test_expression); - % Load and display results + % Load results from workspace + results = evalin('base', 'results'); + passed = evalin('base', 'passed'); + + % Check results if ~passed error('Some tests failed. Check the test results for details.'); end From ec8242cf4d76fa5b539d506c344706869cca8d7e Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:38:17 +0000 Subject: [PATCH 71/77] Update codecov.yml --- .github/workflows/codecov.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index c097d5633b..7949fc11d9 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -1,34 +1,36 @@ name: Code Coverage - on: push: branches: [develop] pull_request: branches: [develop] - jobs: test: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - + - name: Set up MATLAB uses: matlab-actions/setup-matlab@v1 with: release: R2022a - + - name: Install MOcov run: | git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov sudo chmod -R 755 /opt/MOcov - + + - name: Verify MATLAB installation + run: matlab -batch "version" + - name: Run MATLAB tests - run: matlab -batch "run('run_coverage_tests.m')" - + run: | + matlab -batch "addpath(genpath(pwd)); run_coverage_tests" + - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: files: ./coverage.xml flags: matlab token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true From a81aa73dff5bc1dfcb5996698bcca6deb57f7e2a Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:41:32 +0000 Subject: [PATCH 72/77] Update run_coverage_tests.m --- run_coverage_tests.m | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/run_coverage_tests.m b/run_coverage_tests.m index 4fdc4dee78..3e3cb6ba1a 100644 --- a/run_coverage_tests.m +++ b/run_coverage_tests.m @@ -6,19 +6,18 @@ function run_coverage_tests() % Run tests and capture results disp('Running tests with coverage...'); - % Create the expression to run tests with proper variable assignment - test_expression = ['results = runtests(''test/test_myfunction.m'');', ... - 'passed = all([results.Passed]);']; + % Run tests directly first to capture results + results = runtests('test/test_myfunction.m'); + passed = all([results.Passed]); - % Run MOcov with the test expression - mocov('-cover', '.', ... % Use '.' instead of pwd for current directory + % Now run MOcov with a simpler expression that just runs the tests + test_expression = 'runtests(''test/test_myfunction.m'')'; + + % Run MOcov for coverage analysis + mocov('-cover', '.', ... '-cover_xml_file', 'coverage.xml', ... '-expression', test_expression); - % Load results from workspace - results = evalin('base', 'results'); - passed = evalin('base', 'passed'); - % Check results if ~passed error('Some tests failed. Check the test results for details.'); From fd7133ef89e905bc83147c3eb77f728dfe26b010 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:54:18 +0000 Subject: [PATCH 73/77] Update codecov.yml --- .github/workflows/codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 7949fc11d9..ede5e46048 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -34,3 +34,4 @@ jobs: flags: matlab token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true + comment: true From 42c02aec9057ceb3e961e7df24627773f8bd76c0 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:38:22 +0000 Subject: [PATCH 74/77] Delete .github/workflows/testAll-CodeCov-README.md --- .github/workflows/testAll-CodeCov-README.md | 151 -------------------- 1 file changed, 151 deletions(-) delete mode 100644 .github/workflows/testAll-CodeCov-README.md diff --git a/.github/workflows/testAll-CodeCov-README.md b/.github/workflows/testAll-CodeCov-README.md deleted file mode 100644 index 8ca53bc1de..0000000000 --- a/.github/workflows/testAll-CodeCov-README.md +++ /dev/null @@ -1,151 +0,0 @@ - -# TestAll and Code Cov CI - GitHub Actions Workflow - -This repository contains the **Code Cov CI** GitHub Actions workflow, which automates the process of running MATLAB tests and generating code coverage reports using Codecov. The workflow is triggered on pushes and pull requests to the `develop` branch. - -## Table of Contents - -- [Overview](#overview) -- [Prerequisites](#prerequisites) -- [Setup Instructions](#setup-instructions) -- [Workflow Breakdown](#workflow-breakdown) - - [Trigger Configuration](#trigger-configuration) - - [Jobs Definition](#jobs-definition) - - [Steps Breakdown](#steps-breakdown) -- [Project Structure](#project-structure) -- [Benefits](#benefits) -- [License](#license) - -## Overview - -The **Code Cov CI** workflow automates testing and code coverage. It ensures that code changes are tested and that code coverage metrics are updated automatically. - -## Prerequisites - -- **MATLAB R2022a**: The workflow uses MATLAB R2022a. Ensure your code is compatible with this version. -- **Codecov Account**: Sign up for a [Codecov](https://codecov.io/) account to access code coverage reports. -- **Codecov Token**: Obtain a `CODECOV_TOKEN` from Codecov for authentication. - -## Setup Instructions - -1. **Clone the Repository** (if not already): - - ```bash - git clone https://github.com/opencobra/cobratoolbox.git - ``` - -2. **Add the Workflow File**: - - - Save the provided workflow YAML file as `.github/workflows/codecov.yml` in your repository. - -3. **Store Codecov Token**: - - - In the repository, go to **Settings** > **Secrets and variables** > **Actions**. - - Click on **New repository secret**. - - Add `CODECOV_TOKEN` as the name and paste your Codecov token as the value. - -4. **Organize Your Project**: - - - **Source Code**: MATLAB source code in the `src` directory, which it aready is. - - **Tests**: Place test files in the `test` directory. Ensure `testAll.m` is in this directory. - -5. **Push Changes**: - - ```bash - git add . - git commit -m "Add Code Cov CI workflow" - git push origin develop - ``` - -## Workflow Breakdown - -### Trigger Configuration - -The workflow is triggered on push events and pull requests to the `develop` branch. - -```yaml -on: - push: - branches: [develop] - pull_request: - branches: [develop] -``` - -### Jobs Definition - -The workflow defines a job named `test` that runs on the latest Ubuntu environment. - -```yaml -jobs: - test: - runs-on: ubuntu-latest -``` - -### Steps Breakdown - -1. **Checkout Repository** - - Checks out your repository code so the workflow can access it. - - ```yaml - - uses: actions/checkout@v3 - ``` - -2. **Set Up MATLAB** - - Installs MATLAB R2022a on the runner to execute MATLAB scripts and functions. - - ```yaml - - name: Set up MATLAB - uses: matlab-actions/setup-matlab@v1 - with: - release: R2022a - ``` - -3. **Run MATLAB Tests and Generate Coverage** - - Executes the specified MATLAB test and generates a code coverage report in Cobertura XML format. - - ```yaml - - name: Run MATLAB tests and generate coverage - run: | - matlab -batch "import matlab.unittest.TestRunner; \ - import matlab.unittest.plugins.CodeCoveragePlugin; \ - import matlab.unittest.plugins.codecoverage.CoberturaFormat; \ - runner = TestRunner.withTextOutput; \ - runner.addPlugin(CodeCoveragePlugin.forFolder('src', 'Producing', CoberturaFormat('coverage.xml'))); \ - results = runner.run(testsuite('test/testAll.m')); \ - assertSuccess(results);" - ``` - -4. **Upload Coverage to Codecov** - - Uploads the generated code coverage report to Codecov for analysis. - - ```yaml - - name: Upload coverage to Codecov - run: | - bash <(curl -s https://codecov.io/bash) -f coverage.xml -F matlab - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - ``` - - -## Project Structure - -Organize your project as follows: - -``` -your-repository/ -├── .github/ -│ └── workflows/ -│ └── codecov.yml -├── src/ -│ └── (MATLAB source code) -├── test/ -│ └── testAll.m -├ -└── (Other project files) -``` - - From 2fb8c23b5f9dba19179be55fc857b94bc1089ae3 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:38:37 +0000 Subject: [PATCH 75/77] Add files via upload --- ...ode_Coverage_CI_GitHub_Actions_Workflow.md | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 .github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md diff --git a/.github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md b/.github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md new file mode 100644 index 0000000000..a9260df2c1 --- /dev/null +++ b/.github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md @@ -0,0 +1,244 @@ + +# TestAll and Code Coverage CI - GitHub Actions Workflow + +This repository contains the **Code Coverage CI** GitHub Actions workflow, which automates the process of running MATLAB tests and generating code coverage reports using MOcov and Codecov. The workflow is triggered on pushes and pull requests to the `develop` branch. + +## Table of Contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Setup Instructions](#setup-instructions) +- [Workflow Breakdown](#workflow-breakdown) + - [Trigger Configuration](#trigger-configuration) + - [Jobs Definition](#jobs-definition) + - [Steps Breakdown](#steps-breakdown) +- [Project Structure](#project-structure) +- [Benefits](#benefits) +- [License](#license) + +## Overview + +The **Code Coverage CI** workflow automates testing and code coverage reporting. It ensures that code changes are tested and that code coverage metrics are updated automatically using [MOcov](https://github.com/MOxUnit/MOcov) and [Codecov](https://codecov.io/). + +## Prerequisites + +- **MATLAB R2022a**: The workflow uses MATLAB R2022a. Ensure your code is compatible with this version. +- **MOcov**: An open-source code coverage tool for MATLAB. It will be installed as part of the workflow. +- **Codecov Account**: Sign up for a [Codecov](https://codecov.io/) account to access code coverage reports. +- **Codecov Token**: Obtain a `CODECOV_TOKEN` from Codecov for authentication (required for private repositories). + +## Setup Instructions + +1. **Clone the Repository** (if not already): + + ```bash + git clone https://github.com/opencobra/cobratoolbox.git + ``` + +2. **Add the Workflow File**: + + - Save the provided workflow YAML file as `.github/workflows/codecov.yml` in your repository. + +3. **Store Codecov Token**: + + - In the repository, go to **Settings** > **Secrets and variables** > **Actions**. + - Click on **New repository secret**. + - Add `CODECOV_TOKEN` as the name and paste your Codecov token as the value. + +4. **Add MOcov to Your Project** (Optional for local testing): + + - **Clone MOcov**: + + ```bash + git clone https://github.com/MOxUnit/MOcov.git /path/to/MOcov + ``` + + - **Add MOcov to MATLAB Path**: + + ```matlab + addpath(genpath('/path/to/MOcov')); + ``` + +5. **Create `run_coverage_tests.m` Script**: + + - Add the `run_coverage_tests.m` script to the root of your repository. This script runs your tests and generates the coverage report using MOcov. + +6. **Organize Your Project**: + + - **Source Code**: Place your MATLAB source code in the `src` directory. + - **Tests**: Place test files in the `test` directory. Ensure `testAll.m` or your main test script is in this directory. + +7. **Push Changes**: + + ```bash + git add . + git commit -m "Add Code Coverage CI workflow with MOcov" + git push origin develop + ``` + +## Workflow Breakdown + +### Trigger Configuration + +The workflow is triggered on push events and pull requests to the `develop` branch. + +```yaml +on: + push: + branches: [develop] + pull_request: + branches: [develop] +``` + +### Jobs Definition + +The workflow defines a job named `test` that runs on the latest Ubuntu environment. + +```yaml +jobs: + test: + runs-on: ubuntu-latest +``` + +### Steps Breakdown + +1. **Checkout Repository** + + Checks out your repository code so the workflow can access it. + + ```yaml + - uses: actions/checkout@v3 + ``` + +2. **Set Up MATLAB** + + Installs MATLAB R2022a on the runner to execute MATLAB scripts and functions. + + ```yaml + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + with: + release: R2022a + ``` + +3. **Install MOcov** + + Clones the MOcov repository and sets the appropriate permissions. + + ```yaml + - name: Install MOcov + run: | + git clone https://github.com/MOxUnit/MOcov.git /opt/MOcov + sudo chmod -R 755 /opt/MOcov + ``` + +4. **Run MATLAB Tests and Generate Coverage** + + Executes MATLAB tests using MOcov to generate a code coverage report in XML format. + + ```yaml + - name: Run MATLAB tests and generate coverage + run: | + matlab -batch "addpath(genpath(pwd)); run_coverage_tests" + ``` + + **Contents of `run_coverage_tests.m`:** + + ```matlab + function run_coverage_tests() + % Add MOcov to path + addpath(genpath('/opt/MOcov')); + + try + % Run tests and capture results + disp('Running tests with coverage...'); + + % Run tests directly first to capture results + results = runtests('test/testAll.m'); + passed = all([results.Passed]); + + % Now run MOcov with a simpler expression that just runs the tests + test_expression = 'runtests(''test/testAll.m'')'; + + % Run MOcov for coverage analysis + mocov('-cover', '.', ... + '-cover_xml_file', 'coverage.xml', ... + '-expression', test_expression); + + % Check results + if ~passed + error('Some tests failed. Check the test results for details.'); + end + + disp('All tests passed successfully!'); + disp(['Number of passed tests: ' num2str(sum([results.Passed]))]); + + exit(0); + catch e + disp('Error running tests:'); + disp(getReport(e)); + exit(1); + end + end + ``` + +5. **Upload Coverage to Codecov** + + Uploads the generated coverage report to Codecov for analysis. + + ```yaml + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + files: ./coverage.xml + flags: matlab + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + comment: true + ``` + +6. **Optional Debugging Steps** + + You can include these steps to list files and display the coverage report for debugging purposes. + + ```yaml + - name: List workspace files + run: ls -R + + - name: Display coverage.xml + run: cat coverage.xml + ``` + +## Project Structure + +Organize your project as follows: + +``` +your-repository/ +├── .github/ +│ └── workflows/ +│ └── codecov.yml +├── src/ +│ └── (MATLAB source code) +├── test/ +│ └── testAll.m +├── run_coverage_tests.m +└── (Other project files) +``` + +## Benefits + +- **Automated Testing**: Ensures that all code changes are automatically tested. +- **Code Coverage Metrics**: Provides insights into which parts of your codebase are tested. +- **Continuous Integration**: Integrates seamlessly with GitHub Actions for CI/CD workflows. +- **Feedback on Pull Requests**: Codecov can comment on pull requests with coverage reports (requires proper setup and permissions). + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. + +--- + +**Note**: Ensure that your repository has the Codecov GitHub App installed and configured with the necessary permissions to post comments on pull requests. For private repositories, make sure your Codecov account has access to the repository and that the `CODECOV_TOKEN` is correctly set up in your GitHub repository secrets. + +If you encounter issues with Codecov not posting comments on pull requests, refer to the [Codecov documentation](https://docs.codecov.com/docs) or contact [Codecov support](https://community.codecov.io/) for assistance. From 81a2cca0899087787dce073aa320bd9d3b35e6ea Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:39:27 +0000 Subject: [PATCH 76/77] Rename TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md to TestAll_and_Code_Coverage_CI.md --- ...GitHub_Actions_Workflow.md => TestAll_and_Code_Coverage_CI.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md => TestAll_and_Code_Coverage_CI.md} (100%) diff --git a/.github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md b/.github/workflows/TestAll_and_Code_Coverage_CI.md similarity index 100% rename from .github/workflows/TestAll_and_Code_Coverage_CI_GitHub_Actions_Workflow.md rename to .github/workflows/TestAll_and_Code_Coverage_CI.md From ebef82fa586dd3beff1cdd176e804a9032607597 Mon Sep 17 00:00:00 2001 From: AaronBrennan1 <68754265+AaronBrennan1@users.noreply.github.com> Date: Tue, 5 Nov 2024 02:41:13 +0000 Subject: [PATCH 77/77] Update TestAll_and_Code_Coverage_CI.md --- .../workflows/TestAll_and_Code_Coverage_CI.md | 39 +++---------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/.github/workflows/TestAll_and_Code_Coverage_CI.md b/.github/workflows/TestAll_and_Code_Coverage_CI.md index a9260df2c1..43895b6a41 100644 --- a/.github/workflows/TestAll_and_Code_Coverage_CI.md +++ b/.github/workflows/TestAll_and_Code_Coverage_CI.md @@ -13,8 +13,7 @@ This repository contains the **Code Coverage CI** GitHub Actions workflow, which - [Jobs Definition](#jobs-definition) - [Steps Breakdown](#steps-breakdown) - [Project Structure](#project-structure) -- [Benefits](#benefits) -- [License](#license) + ## Overview @@ -37,13 +36,13 @@ The **Code Coverage CI** workflow automates testing and code coverage reporting. 2. **Add the Workflow File**: - - Save the provided workflow YAML file as `.github/workflows/codecov.yml` in your repository. + - Save the provided workflow YAML file as `.github/workflows/codecov.yml` in the repository. 3. **Store Codecov Token**: - In the repository, go to **Settings** > **Secrets and variables** > **Actions**. - Click on **New repository secret**. - - Add `CODECOV_TOKEN` as the name and paste your Codecov token as the value. + - Add `CODECOV_TOKEN` as the name and paste the Codecov token as the value. 4. **Add MOcov to Your Project** (Optional for local testing): @@ -61,9 +60,9 @@ The **Code Coverage CI** workflow automates testing and code coverage reporting. 5. **Create `run_coverage_tests.m` Script**: - - Add the `run_coverage_tests.m` script to the root of your repository. This script runs your tests and generates the coverage report using MOcov. + - Add the `run_coverage_tests.m` script to the root of the repository. This script runs tests and generates the coverage report using MOcov. -6. **Organize Your Project**: +6. **Organize Project**: - **Source Code**: Place your MATLAB source code in the `src` directory. - **Tests**: Place test files in the `test` directory. Ensure `testAll.m` or your main test script is in this directory. @@ -104,7 +103,7 @@ jobs: 1. **Checkout Repository** - Checks out your repository code so the workflow can access it. + Checks out thr repository code so the workflow can access it. ```yaml - uses: actions/checkout@v3 @@ -197,17 +196,7 @@ jobs: comment: true ``` -6. **Optional Debugging Steps** - You can include these steps to list files and display the coverage report for debugging purposes. - - ```yaml - - name: List workspace files - run: ls -R - - - name: Display coverage.xml - run: cat coverage.xml - ``` ## Project Structure @@ -226,19 +215,3 @@ your-repository/ └── (Other project files) ``` -## Benefits - -- **Automated Testing**: Ensures that all code changes are automatically tested. -- **Code Coverage Metrics**: Provides insights into which parts of your codebase are tested. -- **Continuous Integration**: Integrates seamlessly with GitHub Actions for CI/CD workflows. -- **Feedback on Pull Requests**: Codecov can comment on pull requests with coverage reports (requires proper setup and permissions). - -## License - -This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. - ---- - -**Note**: Ensure that your repository has the Codecov GitHub App installed and configured with the necessary permissions to post comments on pull requests. For private repositories, make sure your Codecov account has access to the repository and that the `CODECOV_TOKEN` is correctly set up in your GitHub repository secrets. - -If you encounter issues with Codecov not posting comments on pull requests, refer to the [Codecov documentation](https://docs.codecov.com/docs) or contact [Codecov support](https://community.codecov.io/) for assistance.