From 20e6fd95d02e6a3cd5c94d886d64c3a3e875780b Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 13:14:04 +0200 Subject: [PATCH 01/29] add smoke tests matlab --- run_tests.m | 27 ++++++++++++++++++++ tests/miss_hit.cfg | 22 +++++++++++++++++ tests/test_glmsingleunit.m | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 run_tests.m create mode 100644 tests/miss_hit.cfg create mode 100644 tests/test_glmsingleunit.m diff --git a/run_tests.m b/run_tests.m new file mode 100644 index 0000000..ed4221c --- /dev/null +++ b/run_tests.m @@ -0,0 +1,27 @@ +function run_tests() + + tic; + + cd(fileparts(mfilename('fullpath'))); + + fprintf('\nHome is %s\n', getenv('HOME')); + + folder_to_cover = fullfile(pwd, 'matlab'); + + test_folder = fullfile(pwd, 'tests'); + + success = moxunit_runtests(test_folder, ... + '-verbose', '-recursive', '-with_coverage', ... + '-cover', folder_to_cover, ... + '-cover_xml_file', 'coverage.xml', ... + '-cover_html_dir', fullfile(pwd, 'coverage_html')); + + if success + system('echo 0 > test_report.log'); + else + system('echo 1 > test_report.log'); + end + + toc; + +end diff --git a/tests/miss_hit.cfg b/tests/miss_hit.cfg new file mode 100644 index 0000000..11cf8f9 --- /dev/null +++ b/tests/miss_hit.cfg @@ -0,0 +1,22 @@ +# miss_hit configuration +# for matlab linting and static analysis +# style guide (https://florianschanda.github.io/miss_hit/style_checker.html) +# metrics limit for the code quality (https://florianschanda.github.io/miss_hit/metrics.html) + +project_root + +octave: false + +line_length: 100 + +suppress_rule: "copyright_notice" + +tab_width: 2 + +# snake_case +regex_function_name: "[a-z]+(_[a-z]*)*" + +metric "cnest": limit 4 +metric "file_length": limit 500 +metric "cyc": limit 10 +metric "parameters": limit 5 diff --git a/tests/test_glmsingleunit.m b/tests/test_glmsingleunit.m new file mode 100644 index 0000000..df9066c --- /dev/null +++ b/tests/test_glmsingleunit.m @@ -0,0 +1,50 @@ +function test_suite = test_glmsingleunit %#ok<*STOUT> + + try % assignment of 'localfunctions' is necessary in Matlab >= 2016 + test_functions = localfunctions(); %#ok<*NASGU> + catch % no problem; early Matlab versions can use initTestSuite fine + end + + initTestSuite; + +end + +function test_glmsingleunit_smoke() + + [data, output_dir] = set_up(); + + % GIVEN + design = data.design(1:3); + stimdur = data.stimdur; + tr = data.tr; + data = cellfun(@(x) x(51:70, 8:27, 1, :), data.data(1:3), 'UniformOutput', 0); + + results = GLMestimatesingletrial(design, ... + data, ... + stimdur, ... + tr, ... + output_dir, ... + struct('wantmemoryoutputs', [1 1 1 1])); + + clean_up(); + +end + +function [data, output_dir] = set_up() + + test_dir = fileparts(mfilename('fullpath')); + + data_dir = fullfile(test_dir, 'data'); + data_file = fullfile(data_dir, 'nsdcoreexampledataset.mat'); + + output_dir = fullfile(test_dir, 'outputs', 'matlab'); + + data = load(data_file); + + run(fullfile(test_dir, '..', 'setup.m')); + +end + +function clean_up() + +end From 918091b52bed068a9a77e89592ff78d5afb869bf Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 13:14:39 +0200 Subject: [PATCH 02/29] add matlab test automation --- .github/workflows/run_tests_matlab.yml | 56 ++++++++++++++++++++++++++ .github/workflows/tests_matlab.m | 12 ++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/workflows/run_tests_matlab.yml create mode 100644 .github/workflows/tests_matlab.m diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml new file mode 100644 index 0000000..330cd5c --- /dev/null +++ b/.github/workflows/run_tests_matlab.yml @@ -0,0 +1,56 @@ +name: tests and coverage with matlab + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +jobs: + tests: + runs-on: ubuntu-20.04 + + steps: + - name: Install MATLAB + uses: matlab-actions/setup-matlab@v1.0.1 + with: + # MATLAB release to set up R2020a + release: R2020a + + - name: Shallow clone GLMsingle + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Install Moxunit and MOcov + run: | + git clone https://github.com/MOxUnit/MOxUnit.git --depth 1 + git clone https://github.com/MOcov/MOcov.git --depth 1 + + - name: Prepare data + run: make tests/data/nsdcoreexampledataset.mat + + - name: Run commands + uses: matlab-actions/run-command@v1.0.1 + with: + command: cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); run tests_matlab; + + - name: Run tests + run: | + cat test_report.log | grep 0 + bash <(curl -s https://codecov.io/bash) + + - name: Upload coverage + uses: actions/upload-artifact@v1 + with: + name: coverage_file + path: coverage.xml + + - name: Code coverage + uses: codecov/codecov-action@v1 + with: + file: coverage.xml # optional + flags: matlab # optional + name: codecov-umbrella # optional + fail_ci_if_error: true # optional (default = false) diff --git a/.github/workflows/tests_matlab.m b/.github/workflows/tests_matlab.m new file mode 100644 index 0000000..70f0dca --- /dev/null +++ b/.github/workflows/tests_matlab.m @@ -0,0 +1,12 @@ +root_dir = getenv('GITHUB_WORKSPACE'); + +addpath(fullfile(root_dir, 'MOcov', 'MOcov')); + +cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit')); +run moxunit_set_path(); + +cd(fullfile(root_dir)); + +setup(); + +run run_tests(); From aee01dcf32ac586e897692a9275d02126e3d2391 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 13:15:00 +0200 Subject: [PATCH 03/29] add matlab test demo automation --- .github/workflows/run_demos.m | 8 +++++++ .github/workflows/run_demos_matlab.yml | 31 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 .github/workflows/run_demos.m create mode 100644 .github/workflows/run_demos_matlab.yml diff --git a/.github/workflows/run_demos.m b/.github/workflows/run_demos.m new file mode 100644 index 0000000..15563e4 --- /dev/null +++ b/.github/workflows/run_demos.m @@ -0,0 +1,8 @@ +root_dir = getenv('GITHUB_WORKSPACE'); + +cd(fullfile(root_dir)); + +setup(); + +run matlab/examples/example1; +run matlab/examples/example2; \ No newline at end of file diff --git a/.github/workflows/run_demos_matlab.yml b/.github/workflows/run_demos_matlab.yml new file mode 100644 index 0000000..9097b6c --- /dev/null +++ b/.github/workflows/run_demos_matlab.yml @@ -0,0 +1,31 @@ +name: run matlab demos + +on: + push: + branches: ["*"] + pull_request: + branches: ["*"] + +jobs: + demos: + runs-on: ubuntu-20.04 + + steps: + - name: Install MATLAB + uses: matlab-actions/setup-matlab@v1.0.1 + with: + # MATLAB release to set up R2020a + release: R2020a + + - name: Shallow clone GLMsingle + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + + - name: Run commands + uses: matlab-actions/run-command@v1.0.1 + with: + command: + cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); + run run_demos; From faba452e738ade442721d6e461a8bf093cce11fd Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 16:26:48 +0200 Subject: [PATCH 04/29] add expected data and an assert to system test --- tests/expected/matlab/README.md | 10 ++++++++ tests/expected/matlab/TYPEB_FITHRF.mat | Bin 0 -> 394 bytes .../matlab/TYPEC_FITHRF_GLMDENOISE.mat | Bin 0 -> 394 bytes .../matlab/TYPED_FITHRF_GLMDENOISE_RR.mat | Bin 0 -> 394 bytes tests/test_glmsingleunit.m | 24 ++++++++++++++---- 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 tests/expected/matlab/README.md create mode 100644 tests/expected/matlab/TYPEB_FITHRF.mat create mode 100644 tests/expected/matlab/TYPEC_FITHRF_GLMDENOISE.mat create mode 100644 tests/expected/matlab/TYPED_FITHRF_GLMDENOISE_RR.mat diff --git a/tests/expected/matlab/README.md b/tests/expected/matlab/README.md new file mode 100644 index 0000000..c9b98c6 --- /dev/null +++ b/tests/expected/matlab/README.md @@ -0,0 +1,10 @@ +# Content + +```bash + ├── TYPEB_FITHRF.mat + ├── TYPEC_FITHRF_GLMDENOISE.mat + └── TYPED_FITHRF_GLMDENOISE_RR.mat +``` + +Only contain the `HRFindex` values for `results{2:4}` for +`tests/test_glmsingleunit.m`. diff --git a/tests/expected/matlab/TYPEB_FITHRF.mat b/tests/expected/matlab/TYPEB_FITHRF.mat new file mode 100644 index 0000000000000000000000000000000000000000..2713bea2fbd10764a99a570a46ca220bc6e66575 GIT binary patch literal 394 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3vZ$Vn_o%P-2cQgHY2i*PhE(NSfQGO(~RHc>D#Ffvjg5-`93qo*%Fkj=!%z)&$qx8F19r~!}5 z=SG!nrj;*@1J_tG>)hDzOhTqR`LCFLtfyyP9`Co@+yC-zml;fZD;WH{^w`(?>ptK9 z{rdX%W^G~NZKGTiSZu@6EWx?H}v0O2_+!vBtX3x64V@9I~|I@}Jp_7j?WQ9se zFTd5Sy2?1D9bHtqxjQX3tpQ% z%kn$1JTms+O_!t--Cv^Rchp#%;}9;EIWY0{m)5Pq-C^}^+TFEo33K+WXZ`%Gi2Zt+ G)E)qYubxK$ literal 0 HcmV?d00001 diff --git a/tests/expected/matlab/TYPEC_FITHRF_GLMDENOISE.mat b/tests/expected/matlab/TYPEC_FITHRF_GLMDENOISE.mat new file mode 100644 index 0000000000000000000000000000000000000000..07ac64aaa2b3b2cdc44e3f6af7f326198f8125b2 GIT binary patch literal 394 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3vZ$Vn_o%P-2cQgHY2i*PhE(NSfQGO)BVuuw2EFfvjg5-`93qo*%Fkj=!%z)&$qx8F19r~!}5 z=SG!nrj;*@1J_tG>)hDzOhTqR`LCFLtfyyP9`Co@+yC-zml;fZD;WH{^w`(?>ptK9 z{rdX%W^G~NZKGTiSZu@6EWx?H}v0O2_+!vBtX3x64V@9I~|I@}Jp_7j?WQ9se zFTd5Sy2?1D9bHtqxjQX3tpQ% z%kn$1JTms+O_!t--Cv^Rchp#%;}9;EIWY0{m)5Pq-C^}^+TFEo33K+WXZ`%Gi2Zt+ G)E)qbH=aoV literal 0 HcmV?d00001 diff --git a/tests/expected/matlab/TYPED_FITHRF_GLMDENOISE_RR.mat b/tests/expected/matlab/TYPED_FITHRF_GLMDENOISE_RR.mat new file mode 100644 index 0000000000000000000000000000000000000000..607d66dc150c2ac8c8f1b94b6faa1d8c8df581ea GIT binary patch literal 394 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3vZ$Vn_o%P-2cQgHY2i*PhE(NSfQGBma_G*d7#Ffvjg5-`93qo*%Fkj=!%z)&$qx8F19r~!}5 z=SG!nrj;*@1J_tG>)hDzOhTqR`LCFLtfyyP9`Co@+yC-zml;fZD;WH{^w`(?>ptK9 z{rdX%W^G~NZKGTiSZu@6EWx?H}v0O2_+!vBtX3x64V@9I~|I@}Jp_7j?WQ9se zFTd5Sy2?1D9bHtqxjQX3tpQ% z%kn$1JTms+O_!t--Cv^Rchp#%;}9;EIWY0{m)5Pq-C^}^+TFEo33K+WXZ`%Gi2Zt+ G)E)qTlAc2V literal 0 HcmV?d00001 diff --git a/tests/test_glmsingleunit.m b/tests/test_glmsingleunit.m index df9066c..e23bb5b 100644 --- a/tests/test_glmsingleunit.m +++ b/tests/test_glmsingleunit.m @@ -11,7 +11,7 @@ function test_glmsingleunit_smoke() - [data, output_dir] = set_up(); + [data, expected, output_dir] = set_up_test(); % GIVEN design = data.design(1:3); @@ -25,26 +25,40 @@ function test_glmsingleunit_smoke() tr, ... output_dir, ... struct('wantmemoryoutputs', [1 1 1 1])); + + + assertEqual(results{2}.HRFindex, expected{2}.HRFindex); + assertEqual(results{3}.HRFindex, expected{3}.HRFindex); + assertEqual(results{4}.HRFindex, expected{4}.HRFindex); clean_up(); end -function [data, output_dir] = set_up() +function [data, expected, output_dir] = set_up_test() test_dir = fileparts(mfilename('fullpath')); data_dir = fullfile(test_dir, 'data'); data_file = fullfile(data_dir, 'nsdcoreexampledataset.mat'); - - output_dir = fullfile(test_dir, 'outputs', 'matlab'); - data = load(data_file); + expected_dir = fullfile(test_dir, 'expected', 'matlab'); + load(fullfile(expected_dir, 'TYPEB_FITHRF.mat')) + expected{2}.HRFindex = HRFindex; + load(fullfile(expected_dir, 'TYPEC_FITHRF_GLMDENOISE.mat')) + expected{3}.HRFindex = HRFindex; + load(fullfile(expected_dir, 'TYPED_FITHRF_GLMDENOISE_RR.mat')) + expected{4}.HRFindex = HRFindex; + + output_dir = fullfile(test_dir, 'outputs', 'matlab'); + run(fullfile(test_dir, '..', 'setup.m')); end function clean_up() + + % ununsed for now end From b886a8bb15b65331a14c931f35939d2ed1715277 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 16:34:09 +0200 Subject: [PATCH 05/29] rename test file --- ..._glmsingleunit.m => test_GLMestimatesingletrial.m} | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) rename tests/{test_glmsingleunit.m => test_GLMestimatesingletrial.m} (88%) diff --git a/tests/test_glmsingleunit.m b/tests/test_GLMestimatesingletrial.m similarity index 88% rename from tests/test_glmsingleunit.m rename to tests/test_GLMestimatesingletrial.m index e23bb5b..4699bd7 100644 --- a/tests/test_glmsingleunit.m +++ b/tests/test_GLMestimatesingletrial.m @@ -1,4 +1,4 @@ -function test_suite = test_glmsingleunit %#ok<*STOUT> +function test_suite = test_GLMestimatesingletrial %#ok<*STOUT> try % assignment of 'localfunctions' is necessary in Matlab >= 2016 test_functions = localfunctions(); %#ok<*NASGU> @@ -9,7 +9,10 @@ end -function test_glmsingleunit_smoke() +function test_GLMestimatesingletrial_system() + + % "end-to-end" test of GLMestimatesingletrial + % only checks the HRF index of 400 voxels [data, expected, output_dir] = set_up_test(); @@ -19,6 +22,7 @@ function test_glmsingleunit_smoke() tr = data.tr; data = cellfun(@(x) x(51:70, 8:27, 1, :), data.data(1:3), 'UniformOutput', 0); + % WHEN results = GLMestimatesingletrial(design, ... data, ... stimdur, ... @@ -26,7 +30,8 @@ function test_glmsingleunit_smoke() output_dir, ... struct('wantmemoryoutputs', [1 1 1 1])); - + + % THEN assertEqual(results{2}.HRFindex, expected{2}.HRFindex); assertEqual(results{3}.HRFindex, expected{3}.HRFindex); assertEqual(results{4}.HRFindex, expected{4}.HRFindex); From 04508a5bfb0ace3e5bcc105d67021b0c056066b7 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 16:34:24 +0200 Subject: [PATCH 06/29] add documentation --- CONTRIBUTING.md | 72 ++++++++++++++++++++++++++++++++- Makefile | 8 ++-- tests/expected/matlab/README.md | 4 +- 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index baaa794..9c81194 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,11 @@ Information for anyone who would like to contribute to this repository. ### Makefile +A `Makefile` is used to help set / and automate some things. + +In a terminal type `make help` to see what are the different "recipes" you can +run with this `Makefile`. + ### pre-commit ## Matlab @@ -41,6 +46,71 @@ Information for anyone who would like to contribute to this repository. ### Tests +Running the tests require to have the following toolboes in your MATLAB path: + +- the [MOxUnit testing framework](https://github.com/MOxUnit/MOxUnit) to run the + tests + ([see installation procedure](https://github.com/MOxUnit/MOxUnit#installation)) +- [MOcov](https://github.com/MOcov/MOcov)) to get a code coverage estimate + ([see installation procedure](https://github.com/MOcov/MOcov#installation)) + +All the tests are in the `tests` folder in files starting with `test_*.m`. + +To Download the data required for running the tests (this data is common for +MATLAB and python tests), type: + +```bash +make tests/data/nsdcoreexampledataset.mat +``` + +To run **all** the tests and get code coverage, you can + +1. type the following in a terminal + +``` +make test-matlab +``` + +2. run the `run_tests.m` in MATLAB + +You can also run all the tests contained in a specific `test_*.m` file directly, +by running that file only. + +#### Adding new tests + +A typical MoxUnit test file starts with with `test_` and would look something +like this. + +```matlab +function test_suite=test_sum_of_squares + + try % assignment of 'localfunctions' is necessary in Matlab >= 2016 + test_functions=localfunctions(); + catch % no problem; early Matlab versions can use initTestSuite fine + end + initTestSuite(); + +end + +function test_sum_of_squares_basic + + % given + a = 2; + b = 3; + + % when + result = sum_of_squares([a, b]) + + % then + expected = 13; + assertEqual(result, expected); + +end + +% New tests can added as new sub functions + +``` + #### Demos ### Continuous integration @@ -53,4 +123,4 @@ Information for anyone who would like to contribute to this repository. #### Demos -### Continuous integration \ No newline at end of file +### Continuous integration diff --git a/Makefile b/Makefile index 75e39ce..de24953 100644 --- a/Makefile +++ b/Makefile @@ -47,11 +47,11 @@ install_dev: ## install for both matlab and python developpers pip install -e . pip install -r requirements_dev.txt -lint: lint/black lint/flake8 lint/miss_hit ## check style +lint: lint/black lint/flake8 lint/miss_hit ## check style for MATLAB and python -test: test-matlab test-python +test: test-matlab test-python # run tests with MATLAB and python -tests/data/nsdcoreexampledataset.mat: +tests/data/nsdcoreexampledataset.mat: ## install test data mkdir tests/data curl -fsSL --retry 5 -o "tests/data/nsdcoreexampledataset.mat" https://osf.io/k89b2/download @@ -65,7 +65,7 @@ tests/data/nsdcoreexampledataset.mat: lint/miss_hit: ## lint and checks matlab code mh_style --fix tests && mh_metric --ci tests && mh_lint tests -test-matlab: tests/data/nsdcoreexampledataset.mat +test-matlab: tests/data/nsdcoreexampledataset.mat ## run tests with MATLAB $(MATLAB) $(MATLAB_ARG) -r "run_tests; exit()" coverage-matlab: test-matlab diff --git a/tests/expected/matlab/README.md b/tests/expected/matlab/README.md index c9b98c6..62492d2 100644 --- a/tests/expected/matlab/README.md +++ b/tests/expected/matlab/README.md @@ -6,5 +6,7 @@ └── TYPED_FITHRF_GLMDENOISE_RR.mat ``` -Only contain the `HRFindex` values for `results{2:4}` for +Only contain the expected value `HRFindex` values for `results{2:4}` for `tests/test_glmsingleunit.m`. + +Generated with MATLAB 2017a on Ubuntu 18.04. From b9df9f254c8d53a2902cdc574df15de59ee2cc26 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 16:38:20 +0200 Subject: [PATCH 07/29] lint --- tests/miss_hit.cfg | 2 +- tests/test_GLMestimatesingletrial.m | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/miss_hit.cfg b/tests/miss_hit.cfg index 11cf8f9..ca6e42d 100644 --- a/tests/miss_hit.cfg +++ b/tests/miss_hit.cfg @@ -14,7 +14,7 @@ suppress_rule: "copyright_notice" tab_width: 2 # snake_case -regex_function_name: "[a-z]+(_[a-z]*)*" +regex_function_name: "[a-zA-Z]+(_[a-zA-Z]*)*" metric "cnest": limit 4 metric "file_length": limit 500 diff --git a/tests/test_GLMestimatesingletrial.m b/tests/test_GLMestimatesingletrial.m index 4699bd7..8447d41 100644 --- a/tests/test_GLMestimatesingletrial.m +++ b/tests/test_GLMestimatesingletrial.m @@ -29,8 +29,7 @@ function test_GLMestimatesingletrial_system() tr, ... output_dir, ... struct('wantmemoryoutputs', [1 1 1 1])); - - + % THEN assertEqual(results{2}.HRFindex, expected{2}.HRFindex); assertEqual(results{3}.HRFindex, expected{3}.HRFindex); @@ -49,21 +48,21 @@ function test_GLMestimatesingletrial_system() data = load(data_file); expected_dir = fullfile(test_dir, 'expected', 'matlab'); - load(fullfile(expected_dir, 'TYPEB_FITHRF.mat')) + load(fullfile(expected_dir, 'TYPEB_FITHRF.mat')); expected{2}.HRFindex = HRFindex; - load(fullfile(expected_dir, 'TYPEC_FITHRF_GLMDENOISE.mat')) + load(fullfile(expected_dir, 'TYPEC_FITHRF_GLMDENOISE.mat')); expected{3}.HRFindex = HRFindex; - load(fullfile(expected_dir, 'TYPED_FITHRF_GLMDENOISE_RR.mat')) + load(fullfile(expected_dir, 'TYPED_FITHRF_GLMDENOISE_RR.mat')); expected{4}.HRFindex = HRFindex; output_dir = fullfile(test_dir, 'outputs', 'matlab'); - + run(fullfile(test_dir, '..', 'setup.m')); end function clean_up() - + % ununsed for now end From 0eff10331413befa80c5933541d0f3c2fc17a953 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 16:50:52 +0200 Subject: [PATCH 08/29] remove unneeded upload coverage artefact from CI workflow --- .github/workflows/run_tests_matlab.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml index 330cd5c..7336d33 100644 --- a/.github/workflows/run_tests_matlab.yml +++ b/.github/workflows/run_tests_matlab.yml @@ -41,12 +41,6 @@ jobs: cat test_report.log | grep 0 bash <(curl -s https://codecov.io/bash) - - name: Upload coverage - uses: actions/upload-artifact@v1 - with: - name: coverage_file - path: coverage.xml - - name: Code coverage uses: codecov/codecov-action@v1 with: From 3ab086b9e136de4f4cf6162da0e0d0ce5bddd46f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 17:44:17 +0200 Subject: [PATCH 09/29] run tests matlab demos with CRON job on 1rt and 15th of every month --- .github/workflows/run_demos_matlab.yml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run_demos_matlab.yml b/.github/workflows/run_demos_matlab.yml index 9097b6c..2478a62 100644 --- a/.github/workflows/run_demos_matlab.yml +++ b/.github/workflows/run_demos_matlab.yml @@ -1,10 +1,25 @@ name: run matlab demos +# Uses the cron schedule for github actions +# +# will run at 00H00 run on the 1 and 15 of every month +# +# https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#scheduled-events +# +# ┌───────────── minute (0 - 59) +# │ ┌───────────── hour (0 - 23) +# │ │ ┌───────────── day of the month (1 - 31) +# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC): * means all +# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT): * means all +# │ │ │ │ │ +# │ │ │ │ │ +# │ │ │ │ │ +# +# - cron "0 0 1,15 * *" + on: - push: - branches: ["*"] - pull_request: - branches: ["*"] + schedule: + - cron: "0 0 1,15 * *" jobs: demos: From ef3920e439d38100a3eb5997f3f7bc9dee5bc497 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 18:07:50 +0200 Subject: [PATCH 10/29] add assert on value of R2 --- .../matlab/TYPED_FITHRF_GLMDENOISE_RR.mat | Bin 394 -> 1928 bytes tests/test_GLMestimatesingletrial.m | 3 +++ 2 files changed, 3 insertions(+) diff --git a/tests/expected/matlab/TYPED_FITHRF_GLMDENOISE_RR.mat b/tests/expected/matlab/TYPED_FITHRF_GLMDENOISE_RR.mat index 607d66dc150c2ac8c8f1b94b6faa1d8c8df581ea..8fe22984705b3f3ce55da021664032282063dfa2 100644 GIT binary patch delta 1576 zcmV+@2G{wD1BefhKnyrKFf%$eGaxcBGBS}-BavVQv2+#ze-8iv0QLm{0C=1&lYLYZ zbRWeB3L+%Ri#n7v6o)<{NQo61{JvKL$``bZNW~{`O0!T=iPtR#8yk*|H^(+M7%&;) z5adxoqzBW&M3V?qL`W^cLObR=M1*lp-E%*G+;i{0*O9~F?6Ku=#?7%CXA<)pnR!MbM9dsi9g4dHVskT z+=EDrGGWPJ5q5PfMT@1J0(`k>S>41MC1Yf0e^x`+TYv?YLJZh#!X(@I5c$1=ZueBY zE;1r&u>^L*4tT?35!qY`hTD!JOg?AAmJB@_`^1RZ9E`h(DI|Bl#7>MTvH83jUi@5m zKgz_|yP5E*m107X1Xmk0P}u3wHnbf9L!Kn?aY54=5z+!n5IW09Mh--CRlMezu}fw>I{N_7AqvRmW_a_uKFsC}A(uC42!3xC1_Vi#af9}iZ%1(@2$5Z)_A-knk;f7n)| z!DKlmjFQ|d?kQAZ^ z$6SJMBUEUfX+>Y1>|{BozGU9}e-AU?ktj4CG+-pY2E7hds8C3;@Vc4(f3XJ66ZG&{ zpv7%@1_s7|ds-NT2R&Nsep`d#n+4$C&x7gwE<6YpAbWcpc!NA#2$137R3k=CRY7^L z7+)`0hmhe*^n7;#-c2e(*2H4C9G3xk$;982j_uicEY@n#pip6XXAUCFf4Sf|%HX>< z8iwarncxc!eY#o(zLy&EHRZJ4*+|@sYUUA{1NX~Xyx(nr!m$Y4`2XT`eCx>Za!7zGM*(TXUMSmma5n<;YtmrrEXIuTZW>#c!@SDQusFwf37P;tDSI~?Y+5=F0NmO&#v&Wt!5TFyPfc+D?{nFIN1Jv zoq9IZvoBVCMm2A#Sf%uH@_Cwz$*npVggVqd)?-K^!|~`w0|mff^SJ z1$dq&qqf~IsHwM)(z%r^enmL(K5C&IvLLG7wH8P3M&ZxP-Z=I3|5%JBkEM7gQ^_Y{ zRv%_y)?se=PsLJ_m-I4gM>7-Om7!;3YFfmDB0gJ?7~H91^6Za delta 29 kcmeC+?_!?dz++}*Xl!L@reI`XWHd2Qd13 Date: Thu, 7 Apr 2022 18:08:36 +0200 Subject: [PATCH 11/29] add doc in CI yml and scripts --- .github/workflows/run_tests_matlab.yml | 23 +++++++++++++++++------ .github/workflows/tests_matlab.m | 5 ++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml index 7336d33..d071fa1 100644 --- a/.github/workflows/run_tests_matlab.yml +++ b/.github/workflows/run_tests_matlab.yml @@ -1,40 +1,51 @@ -name: tests and coverage with matlab +name: tests and coverage with MATLAB + +# Installs +# - MATLAB github action +# - MOXunit +# - MOcov +# Get test data +# cd into .github/workflows +# run .github/workflows/tests_matlab.m +# If tests pass, uploads coverage to codecov on: push: + # TODO only run on master branch on push branches: ["*"] pull_request: branches: ["*"] jobs: tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Install MATLAB uses: matlab-actions/setup-matlab@v1.0.1 with: - # MATLAB release to set up R2020a release: R2020a - name: Shallow clone GLMsingle uses: actions/checkout@v3 with: submodules: true - fetch-depth: 0 + fetch-depth: 0 # 0 means we only get the last commit, not the whole git history - name: Install Moxunit and MOcov run: | git clone https://github.com/MOxUnit/MOxUnit.git --depth 1 git clone https://github.com/MOcov/MOcov.git --depth 1 - - name: Prepare data + - name: Download data run: make tests/data/nsdcoreexampledataset.mat - name: Run commands uses: matlab-actions/run-command@v1.0.1 with: - command: cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); run tests_matlab; + command: + cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); + run tests_matlab; - name: Run tests run: | diff --git a/.github/workflows/tests_matlab.m b/.github/workflows/tests_matlab.m index 70f0dca..6ae96d9 100644 --- a/.github/workflows/tests_matlab.m +++ b/.github/workflows/tests_matlab.m @@ -1,12 +1,11 @@ root_dir = getenv('GITHUB_WORKSPACE'); +% MOxUnit and MOcov need to be in the matlab path addpath(fullfile(root_dir, 'MOcov', 'MOcov')); - cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit')); run moxunit_set_path(); +% adds GLM single to the path and runs all the tests cd(fullfile(root_dir)); - setup(); - run run_tests(); From 61cfe71d3f0109545211c0cc99937e4559826d16 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 18:13:49 +0200 Subject: [PATCH 12/29] fix typo --- tests/test_GLMestimatesingletrial.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_GLMestimatesingletrial.m b/tests/test_GLMestimatesingletrial.m index 3a8629e..c42120b 100644 --- a/tests/test_GLMestimatesingletrial.m +++ b/tests/test_GLMestimatesingletrial.m @@ -35,7 +35,7 @@ function test_GLMestimatesingletrial_system() assertEqual(results{3}.HRFindex, expected{3}.HRFindex); assertEqual(results{4}.HRFindex, expected{4}.HRFindex); - assertElementsAlmostEqual(results{4}.R2, expected{4}.HRFindex1, 'absolute', 1e-1); + assertElementsAlmostEqual(results{4}.R2, expected{4}.R2, 'absolute', 1e-1); clean_up(); From bd5d8fab62c79be04309399c1ebe7a78503b09e3 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 18:18:07 +0200 Subject: [PATCH 13/29] add matlab tests badge to README --- .github/workflows/run_tests_matlab.yml | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml index d071fa1..dc0fb1d 100644 --- a/.github/workflows/run_tests_matlab.yml +++ b/.github/workflows/run_tests_matlab.yml @@ -1,4 +1,4 @@ -name: tests and coverage with MATLAB +name: MATLAB tests # Installs # - MATLAB github action diff --git a/README.md b/README.md index 336ed01..f1be3cb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![MATLAB test](https://github.com/cvnlab/GLMsingle/actions/workflows/run_tests_matlab.yml/badge.svg)](https://github.com/cvnlab/GLMsingle/actions/workflows/run_tests_matlab.yml) + # GLMsingle ![image](https://user-images.githubusercontent.com/35503086/151108958-24479034-c7f7-4734-b903-9046ba6a78ac.png) From 956da886744c5cb09d42454fb8da2b9cad7b482e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Thu, 7 Apr 2022 18:19:16 +0200 Subject: [PATCH 14/29] add matlab demo badge to README --- .github/workflows/run_demos_matlab.yml | 2 +- README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_demos_matlab.yml b/.github/workflows/run_demos_matlab.yml index 2478a62..de8f345 100644 --- a/.github/workflows/run_demos_matlab.yml +++ b/.github/workflows/run_demos_matlab.yml @@ -1,4 +1,4 @@ -name: run matlab demos +name: MATLAB demos # Uses the cron schedule for github actions # diff --git a/README.md b/README.md index f1be3cb..e6ba459 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![MATLAB test](https://github.com/cvnlab/GLMsingle/actions/workflows/run_tests_matlab.yml/badge.svg)](https://github.com/cvnlab/GLMsingle/actions/workflows/run_tests_matlab.yml) +[![MATLAB demos](https://github.com/cvnlab/GLMsingle/actions/workflows/run_demos_matlab.yml/badge.svg)](https://github.com/cvnlab/GLMsingle/actions/workflows/run_demos_matlab.yml) # GLMsingle From 9def9a2feff89df0f49c0e2d55dec2bf36285568 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 18:45:22 +0200 Subject: [PATCH 15/29] run demos with MOxUnit in CI so that demo2 is run even if demo1 fails run test demi CI set up through yml undo refactoring fix function name make sure demos run locally use same approach to run tests and demos in CI use similar calls for both tests and demos in CI --- .github/workflows/run_demos.m | 8 ----- .github/workflows/run_demos_ci.m | 22 +++++++++++++ .github/workflows/run_demos_matlab.yml | 15 ++++++--- .../{tests_matlab.m => run_tests_ci.m} | 6 ++-- .github/workflows/run_tests_matlab.yml | 6 ++-- .github/workflows/test_demos.m | 32 +++++++++++++++++++ run_tests.m | 2 ++ 7 files changed, 73 insertions(+), 18 deletions(-) delete mode 100644 .github/workflows/run_demos.m create mode 100644 .github/workflows/run_demos_ci.m rename .github/workflows/{tests_matlab.m => run_tests_ci.m} (71%) create mode 100644 .github/workflows/test_demos.m diff --git a/.github/workflows/run_demos.m b/.github/workflows/run_demos.m deleted file mode 100644 index 15563e4..0000000 --- a/.github/workflows/run_demos.m +++ /dev/null @@ -1,8 +0,0 @@ -root_dir = getenv('GITHUB_WORKSPACE'); - -cd(fullfile(root_dir)); - -setup(); - -run matlab/examples/example1; -run matlab/examples/example2; \ No newline at end of file diff --git a/.github/workflows/run_demos_ci.m b/.github/workflows/run_demos_ci.m new file mode 100644 index 0000000..5cc0271 --- /dev/null +++ b/.github/workflows/run_demos_ci.m @@ -0,0 +1,22 @@ +% run demos with moxunit in github CI + +root_dir = getenv('GITHUB_WORKSPACE'); + +% MOxUnit and MOcov need to be in the matlab path +addpath(fullfile(root_dir, 'MOcov', 'MOcov')); +cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit')); +run moxunit_set_path(); + +% add glm single to path +cd(root_dir) +setup(); + +this_folder = fileparts(mfilename('fullpath')); +test_folder = this_folder; +success = moxunit_runtests(test_folder, '-verbose', '-recursive'); + +if success + system('echo 0 > test_report.log'); +else + system('echo 1 > test_report.log'); +end diff --git a/.github/workflows/run_demos_matlab.yml b/.github/workflows/run_demos_matlab.yml index de8f345..3156175 100644 --- a/.github/workflows/run_demos_matlab.yml +++ b/.github/workflows/run_demos_matlab.yml @@ -20,6 +20,9 @@ name: MATLAB demos on: schedule: - cron: "0 0 1,15 * *" + push: + # TODO only run on master branch on push + branches: ["*"] jobs: demos: @@ -29,18 +32,22 @@ jobs: - name: Install MATLAB uses: matlab-actions/setup-matlab@v1.0.1 with: - # MATLAB release to set up R2020a release: R2020a - name: Shallow clone GLMsingle uses: actions/checkout@v3 with: submodules: true - fetch-depth: 0 + fetch-depth: 0 # 0 means we only get the last commit, not the whole git history + + - name: Install Moxunit and MOcov + run: | + git clone https://github.com/MOxUnit/MOxUnit.git --depth 1 + git clone https://github.com/MOcov/MOcov.git --depth 1 - name: Run commands uses: matlab-actions/run-command@v1.0.1 with: command: - cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); - run run_demos; + cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); + run run_demos_ci; diff --git a/.github/workflows/tests_matlab.m b/.github/workflows/run_tests_ci.m similarity index 71% rename from .github/workflows/tests_matlab.m rename to .github/workflows/run_tests_ci.m index 6ae96d9..95ea322 100644 --- a/.github/workflows/tests_matlab.m +++ b/.github/workflows/run_tests_ci.m @@ -1,3 +1,5 @@ +% run tests with code coverage via the run_tests scripts in the root folder. + root_dir = getenv('GITHUB_WORKSPACE'); % MOxUnit and MOcov need to be in the matlab path @@ -5,7 +7,5 @@ cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit')); run moxunit_set_path(); -% adds GLM single to the path and runs all the tests -cd(fullfile(root_dir)); -setup(); +cd(root_dir) run run_tests(); diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml index dc0fb1d..f62fdc0 100644 --- a/.github/workflows/run_tests_matlab.yml +++ b/.github/workflows/run_tests_matlab.yml @@ -40,14 +40,14 @@ jobs: - name: Download data run: make tests/data/nsdcoreexampledataset.mat - - name: Run commands + - name: Run tests uses: matlab-actions/run-command@v1.0.1 with: command: cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); - run tests_matlab; + run run_tests_ci; - - name: Run tests + - name: Check logs run: | cat test_report.log | grep 0 bash <(curl -s https://codecov.io/bash) diff --git a/.github/workflows/test_demos.m b/.github/workflows/test_demos.m new file mode 100644 index 0000000..be3cc99 --- /dev/null +++ b/.github/workflows/test_demos.m @@ -0,0 +1,32 @@ +function test_suite = test_demos %#ok<*STOUT> + + try % assignment of 'localfunctions' is necessary in Matlab >= 2016 + test_functions = localfunctions(); %#ok<*NASGU> + catch % no problem; early Matlab versions can use initTestSuite fine + end + + initTestSuite; + +end + +function test_demo1() + + run(fullfile(root_dir(), 'matlab', 'examples', 'example1')); + +end + +function test_demo2() + + run(fullfile(root_dir(), 'matlab', 'examples', 'example2')); + +end + +function value = root_dir() + + value = getenv('GITHUB_WORKSPACE'); + + if isempty(value) + value = fullfile(fileparts(mfilename('fullpath')), '..', '..'); + end + +end diff --git a/run_tests.m b/run_tests.m index ed4221c..9ee5f41 100644 --- a/run_tests.m +++ b/run_tests.m @@ -1,5 +1,7 @@ function run_tests() + % run tests with code coverage + tic; cd(fileparts(mfilename('fullpath'))); From c4530c312d500bf99ba5b879def000cf5909d13f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 18:50:40 +0200 Subject: [PATCH 16/29] force demos to fail to make sure this is picked by CI --- matlab/examples/example1.m | 2 ++ matlab/examples/example2.m | 2 ++ 2 files changed, 4 insertions(+) diff --git a/matlab/examples/example1.m b/matlab/examples/example1.m index 96f836f..7abbae5 100644 --- a/matlab/examples/example1.m +++ b/matlab/examples/example1.m @@ -1,3 +1,5 @@ +error('this is a test') + %% Example 1 Overview % % GLMsingle is new tool that provides efficient, scalable, and accurate diff --git a/matlab/examples/example2.m b/matlab/examples/example2.m index a2dcdc7..077a2cf 100644 --- a/matlab/examples/example2.m +++ b/matlab/examples/example2.m @@ -1,3 +1,5 @@ +error('this is a test') + %% Example 2 Overview % % GLMsingle is new tool that provides efficient, scalable, and accurate From 10161f026974975194c5201e996957545fdbf45f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 18:56:15 +0200 Subject: [PATCH 17/29] add a check log to try to show workflow as failed --- .../workflows/{run_demos_matlab.yml => run_demos_matlab.yaml} | 4 ++++ .../workflows/{run_tests_matlab.yml => run_tests_matlab.yaml} | 0 2 files changed, 4 insertions(+) rename .github/workflows/{run_demos_matlab.yml => run_demos_matlab.yaml} (95%) rename .github/workflows/{run_tests_matlab.yml => run_tests_matlab.yaml} (100%) diff --git a/.github/workflows/run_demos_matlab.yml b/.github/workflows/run_demos_matlab.yaml similarity index 95% rename from .github/workflows/run_demos_matlab.yml rename to .github/workflows/run_demos_matlab.yaml index 3156175..36f391f 100644 --- a/.github/workflows/run_demos_matlab.yml +++ b/.github/workflows/run_demos_matlab.yaml @@ -51,3 +51,7 @@ jobs: command: cd(fullfile(getenv('GITHUB_WORKSPACE'), '.github', 'workflows')); run run_demos_ci; + + - name: Check logs + run: | + cat test_report.log | grep 0 \ No newline at end of file diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yaml similarity index 100% rename from .github/workflows/run_tests_matlab.yml rename to .github/workflows/run_tests_matlab.yaml From f569dd6ea7a2862d05628998b1b1c75c3c37d0e7 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 19:01:20 +0200 Subject: [PATCH 18/29] remove forced errors in demo and reset to run demos bimonthly --- .github/workflows/run_demos_matlab.yaml | 3 --- matlab/examples/example1.m | 2 -- matlab/examples/example2.m | 2 -- 3 files changed, 7 deletions(-) diff --git a/.github/workflows/run_demos_matlab.yaml b/.github/workflows/run_demos_matlab.yaml index 36f391f..7aa9ee3 100644 --- a/.github/workflows/run_demos_matlab.yaml +++ b/.github/workflows/run_demos_matlab.yaml @@ -20,9 +20,6 @@ name: MATLAB demos on: schedule: - cron: "0 0 1,15 * *" - push: - # TODO only run on master branch on push - branches: ["*"] jobs: demos: diff --git a/matlab/examples/example1.m b/matlab/examples/example1.m index 7abbae5..96f836f 100644 --- a/matlab/examples/example1.m +++ b/matlab/examples/example1.m @@ -1,5 +1,3 @@ -error('this is a test') - %% Example 1 Overview % % GLMsingle is new tool that provides efficient, scalable, and accurate diff --git a/matlab/examples/example2.m b/matlab/examples/example2.m index 077a2cf..a2dcdc7 100644 --- a/matlab/examples/example2.m +++ b/matlab/examples/example2.m @@ -1,5 +1,3 @@ -error('this is a test') - %% Example 2 Overview % % GLMsingle is new tool that provides efficient, scalable, and accurate From 26389af56b520d745ed4404e5ae83821aceb639c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 19:15:05 +0200 Subject: [PATCH 19/29] add doc on running tests and demos in CI --- CONTRIBUTING.md | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c81194..9dc12ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,7 +71,10 @@ To run **all** the tests and get code coverage, you can make test-matlab ``` -2. run the `run_tests.m` in MATLAB +1. run `moxunit_runtests` in MATLAB to run all `test_*.m` files in in the + present working directory. + +1. run the `run_tests.m` in MATLAB You can also run all the tests contained in a specific `test_*.m` file directly, by running that file only. @@ -111,10 +114,30 @@ end ``` -#### Demos - ### Continuous integration +#### Tests + +The matlab tests are run by the workflow: +`.github/workflows/run_tests_matlab.yaml`. It sets up MATLAB, Moxunit and Mocov +and then then calls `.github/workflows/run_tests_ci.m` to run the tests via +`run_tests.m`. + +Those tests should be run with every push on the `master` branch and on pull +request that target the `master` branch. + +### Demos + +The demos in the `matlab/examples` folder are run automatically in Github CI at +regular intervals. + +The matlab demos are run by the workflow: +`.github/workflows/run_demos_matlab.yaml`. The demos are run by calling +`.github/workflows/run_demos_ci.m` and also each demo is run via a MoxUnit test +(see `.github/workflows/test_demos.m`) to make sure that if the first one +crashes, then the second one will still be run (easier than setting up parallel +jobs in CI). + ## Python ### Style guide From 56807a6ca73b7afae710ad17bd994aa20266ad88 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 19:18:22 +0200 Subject: [PATCH 20/29] miss_hit lint CI code --- .github/workflows/miss_hit.cfg | 23 +++++++++++++++++++++++ .github/workflows/run_demos_ci.m | 2 +- .github/workflows/run_tests_ci.m | 2 +- .github/workflows/test_demos.m | 16 ++++++++-------- Makefile | 1 + 5 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/miss_hit.cfg diff --git a/.github/workflows/miss_hit.cfg b/.github/workflows/miss_hit.cfg new file mode 100644 index 0000000..d02fa5c --- /dev/null +++ b/.github/workflows/miss_hit.cfg @@ -0,0 +1,23 @@ +# miss_hit configuration +# for matlab linting and static analysis +# style guide (https://florianschanda.github.io/miss_hit/style_checker.html) +# metrics limit for the code quality (https://florianschanda.github.io/miss_hit/metrics.html) + +project_root + +octave: false + +line_length: 100 + +suppress_rule: "copyright_notice" + +tab_width: 2 + +# snake_case +regex_script_name: "[a-zA-Z]+(_[a-zA-Z0-9]*)*" +regex_function_name: "[a-zA-Z]+(_[a-zA-Z0-9]*)*" + +metric "cnest": limit 4 +metric "file_length": limit 500 +metric "cyc": limit 10 +metric "parameters": limit 5 diff --git a/.github/workflows/run_demos_ci.m b/.github/workflows/run_demos_ci.m index 5cc0271..704836c 100644 --- a/.github/workflows/run_demos_ci.m +++ b/.github/workflows/run_demos_ci.m @@ -8,7 +8,7 @@ run moxunit_set_path(); % add glm single to path -cd(root_dir) +cd(root_dir); setup(); this_folder = fileparts(mfilename('fullpath')); diff --git a/.github/workflows/run_tests_ci.m b/.github/workflows/run_tests_ci.m index 95ea322..ecf8798 100644 --- a/.github/workflows/run_tests_ci.m +++ b/.github/workflows/run_tests_ci.m @@ -7,5 +7,5 @@ cd(fullfile(root_dir, 'MOxUnit', 'MOxUnit')); run moxunit_set_path(); -cd(root_dir) +cd(root_dir); run run_tests(); diff --git a/.github/workflows/test_demos.m b/.github/workflows/test_demos.m index be3cc99..64e73ba 100644 --- a/.github/workflows/test_demos.m +++ b/.github/workflows/test_demos.m @@ -1,30 +1,30 @@ function test_suite = test_demos %#ok<*STOUT> - try % assignment of 'localfunctions' is necessary in Matlab >= 2016 - test_functions = localfunctions(); %#ok<*NASGU> - catch % no problem; early Matlab versions can use initTestSuite fine - end + try % assignment of 'localfunctions' is necessary in Matlab >= 2016 + test_functions = localfunctions(); %#ok<*NASGU> + catch % no problem; early Matlab versions can use initTestSuite fine + end - initTestSuite; + initTestSuite; end function test_demo1() - run(fullfile(root_dir(), 'matlab', 'examples', 'example1')); + run(fullfile(root_dir(), 'matlab', 'examples', 'example1')); end function test_demo2() - run(fullfile(root_dir(), 'matlab', 'examples', 'example2')); + run(fullfile(root_dir(), 'matlab', 'examples', 'example2')); end function value = root_dir() value = getenv('GITHUB_WORKSPACE'); - + if isempty(value) value = fullfile(fileparts(mfilename('fullpath')), '..', '..'); end diff --git a/Makefile b/Makefile index de24953..2e3a9ac 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ tests/data/nsdcoreexampledataset.mat: ## install test data lint/miss_hit: ## lint and checks matlab code mh_style --fix tests && mh_metric --ci tests && mh_lint tests + mh_style --fix .github/workflows && mh_metric --ci .github/workflows && mh_lint .github/workflows test-matlab: tests/data/nsdcoreexampledataset.mat ## run tests with MATLAB $(MATLAB) $(MATLAB_ARG) -r "run_tests; exit()" From 07da5c3ae7780ae609f800b205b77760454b2bcc Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 19:23:33 +0200 Subject: [PATCH 21/29] add miss hit and linting documentation --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9dc12ca..0c27c29 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,6 +44,46 @@ run with this `Makefile`. ### Style guide +The [`miss_hit` python package](https://misshit.org/) is used to help ensure a +consistent coding style for some of the MATLAB code. + +`miss_hit` can check code style, do a certain amount of automatic code +reformating and prevent the code complexity from getting out of hand by running +static code analysis (Static analysis can is a way to measure and track software +quality metrics without additional code like tests). + +`miss_hit` is quite configurable via the use of `miss_hit.cfg` files. + +Install `miss_hit`: + +```bash +$ pip3 install miss_hit +``` + +It is also included in `requirements_dev.txt`, so it will by running: + +```bash +$ pip3 install -r requirements_dev.txt +``` + +Style-check your program: + +```bash +$ mh_style --fix path_to_folder_or_m_file +``` + +Make sure your code does not get too complex: + +```bash +$ mh_metric --ci +``` + +You can rule several of those checks by simply typing + +```bash +make lint/miss_hit +``` + ### Tests Running the tests require to have the following toolboes in your MATLAB path: From 1908552d4977f42dcbe7e002dcabf894720e99b9 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 20:58:29 +0200 Subject: [PATCH 22/29] add pre-commit doc --- CONTRIBUTING.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c27c29..e83b010 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,31 @@ run with this `Makefile`. ### pre-commit +You can use the [`pre-commit` python package](https://pre-commit.com/) in this +repo to make sure you only commit properly formatted files (for example `.yml` +files). + +1. Install `pre-commit` + +```bash +$ pip3 install pre-commit +``` + +It is also included in `requirements_dev.txt`, so it will installed by running: + +```bash +$ pip3 install -r requirements_dev.txt +``` + +The `.pre-commit-config.yml` file defines the checks to run when committing +files. + +1. Run the following command to install the `pre-commit` "hooks" + +```bash +$ pre-commit install +``` + ## Matlab ### Style guide @@ -60,7 +85,7 @@ Install `miss_hit`: $ pip3 install miss_hit ``` -It is also included in `requirements_dev.txt`, so it will by running: +It is also included in `requirements_dev.txt`, so it will installed by running: ```bash $ pip3 install -r requirements_dev.txt From 70d205e701e7b3fc3482432057cb140885894b30 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:04:16 +0200 Subject: [PATCH 23/29] update contributors doc --- CONTRIBUTING.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e83b010..25c0a2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,24 @@ Information for anyone who would like to contribute to this repository. +- [CONTRIBUTING](#contributing) + - [Repository map](#repository-map) + - [Generic](#generic) + - [Makefile](#makefile) + - [pre-commit](#pre-commit) + - [Matlab](#matlab) + - [Style guide](#style-guide) + - [Tests](#tests) + - [Adding new tests](#adding-new-tests) + - [Continuous integration](#continuous-integration) + - [Tests](#tests-1) + - [Demos](#demos) + - [Python](#python) + - [Style guide](#style-guide-1) + - [Tests](#tests-2) + - [Demos](#demos-1) + - [Continuous integration](#continuous-integration-1) + ## Repository map ```bash @@ -35,8 +53,11 @@ Information for anyone who would like to contribute to this repository. A `Makefile` is used to help set / and automate some things. -In a terminal type `make help` to see what are the different "recipes" you can -run with this `Makefile`. +In a terminal type `make help` to see what some of the different "recipes" you +can run with this `Makefile`. + +See +[here for a short intro on using `Makefiles`](https://the-turing-way.netlify.app/reproducible-research/make.html) ### pre-commit @@ -111,7 +132,10 @@ make lint/miss_hit ### Tests -Running the tests require to have the following toolboes in your MATLAB path: +For an introduction to testing see +[here](https://the-turing-way.netlify.app/reproducible-research/make.html). + +Running the tests require to have the following toolboxes in your MATLAB path: - the [MOxUnit testing framework](https://github.com/MOxUnit/MOxUnit) to run the tests @@ -181,6 +205,8 @@ end ### Continuous integration +We use Github to run several workflows for continuous integration. + #### Tests The matlab tests are run by the workflow: @@ -191,7 +217,7 @@ and then then calls `.github/workflows/run_tests_ci.m` to run the tests via Those tests should be run with every push on the `master` branch and on pull request that target the `master` branch. -### Demos +#### Demos The demos in the `matlab/examples` folder are run automatically in Github CI at regular intervals. From 731ac95261d2e2369f901259c3e1eeec6311afe9 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:21:20 +0200 Subject: [PATCH 24/29] add doc on generating and chekcing test data --- tests/expected/matlab/README.md | 20 ++++++++++++++++++-- tests/expected/matlab/histogram_R2.tif | Bin 0 -> 353585 bytes tests/expected/matlab/sanity_checks.m | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/expected/matlab/histogram_R2.tif create mode 100644 tests/expected/matlab/sanity_checks.m diff --git a/tests/expected/matlab/README.md b/tests/expected/matlab/README.md index 62492d2..604e4d9 100644 --- a/tests/expected/matlab/README.md +++ b/tests/expected/matlab/README.md @@ -1,12 +1,28 @@ # Content +Data used for the expected results of the system tests. + ```bash ├── TYPEB_FITHRF.mat ├── TYPEC_FITHRF_GLMDENOISE.mat └── TYPED_FITHRF_GLMDENOISE_RR.mat ``` -Only contain the expected value `HRFindex` values for `results{2:4}` for -`tests/test_glmsingleunit.m`. +Contain the expected value for: + +- `HRFindex` values for `results{2:4}` for `tests/test_glmsingleunit.m`. + +`TYPED_FITHRF_GLMDENOISE_RR.mat` also contains `R2` values. Generated with MATLAB 2017a on Ubuntu 18.04. + +If new expected data needs to be generated, this can be done from the output of +`tests/test_GLMestimatesingletrial.m` that will be saved in `tests/outputs`. + +Some basic sanity checks can be run on those data with +`tests/expected/matlab/sanity_checks.m` + +- like making sure that the there is nothing "strange" in the range of R2 values + tested. + +![histogram_R2](./histogram_R2.tif) diff --git a/tests/expected/matlab/histogram_R2.tif b/tests/expected/matlab/histogram_R2.tif new file mode 100644 index 0000000000000000000000000000000000000000..d207718c39bb04aeaaeca14ff82ae9bde913d5ec GIT binary patch literal 353585 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 literal 0 HcmV?d00001 diff --git a/tests/expected/matlab/sanity_checks.m b/tests/expected/matlab/sanity_checks.m new file mode 100644 index 0000000..7a04f00 --- /dev/null +++ b/tests/expected/matlab/sanity_checks.m @@ -0,0 +1,21 @@ +% make sure we have no NaN / Inf in our expected results +% aslo plots a couple of figures for quick visual inspection + +clear +clc +close all + +load('TYPED_FITHRF_GLMDENOISE_RR.mat') + +assert(any(isnan(R2(:))) == 0); +assert(any(isinf(R2(:))) == 0); + +figure('name', 'histogram R2') +hist(R2(:), 100); +print('histogram_R2.tif', '-depsc','-tiff'); + +figure('name', 'R2') +imagesc(R2, [0 100]) + +figure('name', 'HRFindex') +imagesc(HRFindex, [1 20]) \ No newline at end of file From a31257919e70712de6449e53e079229413e73b49 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:26:07 +0200 Subject: [PATCH 25/29] update repo map --- CONTRIBUTING.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25c0a2e..60176c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,10 +26,10 @@ Information for anyone who would like to contribute to this repository. ├── .git ├── .github │ └── workflows # Github continuous integration set up -├── examples +├── examples # Python demos │ ├── data │ ├── example1outputs -│ ├── example2outputs +│ └── example2outputs ├── glmsingle # Python implementation │ ├── cod │ ├── design @@ -39,11 +39,13 @@ Information for anyone who would like to contribute to this repository. │ ├── ssq │ └── utils ├── matlab # Matlab implementation -│ ├── examples -│ ├── fracridge +│ ├── examples # Matlab demos +│ ├── fracridge # Fracridge submodule │ └── utilities └── tests # Python and Matlab tests - └── data + ├── data # Data used as inputs for the tests + └── expected # Expected results of the tests +│ └── matlab ``` @@ -152,6 +154,9 @@ MATLAB and python tests), type: make tests/data/nsdcoreexampledataset.mat ``` +Only some specfici results are checked by the system tests: those can be found +in `tests/expected/matlab` + To run **all** the tests and get code coverage, you can 1. type the following in a terminal From b35bec6f7759a0681e9baa73c44b565124777bab Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:44:20 +0200 Subject: [PATCH 26/29] switch to using png image in doc --- CONTRIBUTING.md | 5 +++-- tests/expected/matlab/README.md | 2 +- tests/expected/matlab/histogram_R2.png | Bin 0 -> 11899 bytes tests/expected/matlab/histogram_R2.tif | Bin 353585 -> 0 bytes tests/expected/matlab/sanity_checks.m | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 tests/expected/matlab/histogram_R2.png delete mode 100644 tests/expected/matlab/histogram_R2.tif diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60176c6..94480c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,8 +154,9 @@ MATLAB and python tests), type: make tests/data/nsdcoreexampledataset.mat ``` -Only some specfici results are checked by the system tests: those can be found -in `tests/expected/matlab` +Only some specific results are checked by the system tests: those can be found +in `tests/expected/matlab`. See this [README](./tests/expected/matlab/README.md) +for more information. To run **all** the tests and get code coverage, you can diff --git a/tests/expected/matlab/README.md b/tests/expected/matlab/README.md index 604e4d9..158f6a2 100644 --- a/tests/expected/matlab/README.md +++ b/tests/expected/matlab/README.md @@ -25,4 +25,4 @@ Some basic sanity checks can be run on those data with - like making sure that the there is nothing "strange" in the range of R2 values tested. -![histogram_R2](./histogram_R2.tif) +![histogram_R2](./histogram_R2.png) diff --git a/tests/expected/matlab/histogram_R2.png b/tests/expected/matlab/histogram_R2.png new file mode 100644 index 0000000000000000000000000000000000000000..60dbe6fd576a46dd0cf747a1cddeae0c090644f5 GIT binary patch literal 11899 zcmdsd2{hFG{{OcXNjwxvNZCqg6WKsol`q(MCV2VrwLW8#h=eB8`GYi!~h;Z+EWho<&PmVx!GJd$#I z-ILSdDN&D;#vXdk)*fCKZdgS7xc<50>ic);U&Zdyw(z)W=8g5t%4_jxaUHZ0;Smc0$^l=wA=|cw&9olv1pyH7OigJesQ}B2M*@bAHIIiy< zGv0-BX`YQ;nDRP!P$T8cdkg-{DWA{sZl_&Xt8V+@2KL)sZ9k*r&vUPeU3UGdcslaZ zgNx~m3w3sABJoy>fa8T^m2HAq=h(X+O5GAT&i3rc^(%GZM^D&Exm#VXn5J72m6o+L zMC#=i9WuhoF%^EO0v{~JVn%d%bX|FvFeid=m0V9`L6B!FTm%F;u}5YNa_5xkT7>If z?s{a`4p%lr?MN>-a{X$l7=kq1(L#{tzx)@xaIco{by4i0r{f(tIoa8_xnAkUn-8Ve zM9Y(>E2X5RrMGR{W?6neR`Hr07K@d=&xX|7_eH-yaQ$<#QJP7nbt}oN{Jvln z>4==%HPx}NA8yVJ)Yv;XRAY7?xmr)3r=WbMzjgC(MV{&IZ73+qaq7y4cTCU-s(o_s zMRbW%!Fcw^j~}C=qT*L*gGyc#4p*-}fxng~$tWCyMqi$vZ-0j%0VjhQ{TWF~!^P~f z`(M z=eWFcFE6%bjGa0v&%!AbgLy21pXw_Q;_CJtO>L4FLezu}p1Zd3^p%InN=Yes44qeu zt;J9Z{k&K$I&)pwYBnI}-UyUsB5G{h zgf3fKTc3%%!MTYpCI5x*5BHpAEY{(i931?IUlPR6Jvne~qIa&TJ#=@59=M zM5OMu_9R|yi+XO5fwP`|Qgx$+WY*EysqEPP&eY^Km+JJxu>F_bN#fJp`YXSkT8Btp z?9F&)gb9$tAAlp>GHPV%dXhDvq+<@+p%g1$du%XA;=<}QG~em zCXp0$4k;^34o81mE>sn}2~jKJ4p6UqER8lyy%b44WK$b6#*%4W6Q$sKh1CKMM|k;5 z`BBGqeIp~UCT)2GBO_r&kD(-DoSlOM?JEmP!E2&({lG><(n)NoyH~boq1TAK^jStX ze=yEZb-At18s%hfUocs;9OvB|4E5E&<#ke$$=fSspC0ZhSmBN2Z&G(H@<7*g&OoEYY%x9?kJZ$MC;FUR zf5zC*HfdZZx;LW2fl^cmw+MeAV2SEe}ETuuC ziQx7384RUM#CbnYNJx0~YM|k?aE;JTb$%6J4@XBwS&mIeJ@L_1Q%{~pi%?bD)Q$5! zY)SjqAVarpLiwm41)Pt_%j1SLgm=I%u!_X$sw*;X85 zCLT2y<8GK{PS;(b>Yl#8Q`1)sx&B=5d05_9@akYl_nPdsZF;3bt=DKPD+%JHcr29Zsc?4P!`3|hT&L9TW^-KN&y=GBz8;fFo4X3vm8PnMvPSGlUb6T>6 z9>uwj!jbcv@@e-l8D+yxQ#WpJ-p;Mgui$byNWL$xH$gzizLQJc`}+r$nN}l` z>2~$pfhha%?d-_2JCQ>?zS$0K;Q{lp%%Nh1dLn1vQX0&YDcsuHnugACnjQI!TPP8> zv$yZ)=n%%yrdrMY982%~lGnEe`Lwqo*TL4dE!{$cadx7KhSD@NG=x(|(Ff$od4cq$ z+0j-TzO?+2H`}BPH^T+CzS@8cNu50+W54?FbNlu{L_@JtdJCc^BIN#Gimv|&19&8+ zq85JWY4zNA2TW28)+VAZs%NSr+i`U91A>UXKGEj}2W{Vy(w1f4`qr{MLrPm)yDPpQ zW<9NuQ1nQL=;w9-QM29m7jO--F?sJjl?M~@5^*guGzy37oY((2R>`Y~HeE$oVa)rv z(O!h9wtxAOd!;O-NrfL#i#L4k6-vCA6emopRhsmN!cR?3UM`hTbzM3I@4<4GDoc>) z7oaSB{O#9ug#9Mr)LjTtrehlSTZFD^9#nf-D4&smftU(AqV|>tkj>Gt5H8@=xu+M6 zj0n{I(B*2usskB86Ypngp_S&lyyDy2lu#K>_WWzqR@^Vv^$*PhhA_WxxL@w;-qK*r%^Q&V zK^S`3@7@7Uir~cNhviyLBT7#o2>p2QN35gc_}&foy9doiI~Vy(^_CSL6hqW7de2?+u8p<` zDtX@JKiC_tC1X)t{_2Igmhpf&pdT}fBxH`ba zufP48R*NUo*FD5nDyBIOfY8iVj741Y^GIZ?Owq|nEtFT8U3*@hq z-l+|ZkkBQ)eti{=!qHI>IE^ho2l9+_#$hTVqQdIX({rpA-@ks)tXqqm_bBbJFd+v9 zD8`cD@%r@{UtR!|Juyaq9U{(Y7R#)()4$&58luV0nY+#ouq&Avw=S7~? zN&X$C*pu?amyi4T`OVz~z2a4bmkpc>CAtF$t0n=>%U*pfTapSU@<&MpB(DJ=2EzY} z^37?&WYr8qkopa-Z4xgpCMBLmkf9s@OZralF%_Yn*%x^hpjk(UAm0TaR_61TD>QfP z@a@|LZo)ZuESt_+HO_vDN04_;H*xri$R@AQbw5L4R)!1h(tLW(dUBi&_`QRJ2GwRfI6TSD|GJ*$dmYN)+0k&03}9g=7qrD%?doB3-=c^Ha9o-Kh#Ch zsTtTRw;=k^X;c*O`T3&x!jO;<^Qdjevq{OnKvZ-IFpLbVitx(HN){pS%Y(JCvhTka zgTTZDF7^YTFK9glyg=ix&{c43tb@YvWVHbC17&*6$7d0^sIc!)f_t6HJP3z&;Iqyg z>>yZSy1crWG(9~%5$3Zzp5rz4&weEYy z(x?cYjYr(WxK1@e!taN$@tdFE5ZNrGoLjQ=y{ANj6~>d+WpR*~;xg<@AoBRt6;^07 zN+}q?5fQvb&=#=+JcydBR0Co6Nbua;99QwP<2Un_-Xi zhKKwk1V&Ar@cbkWH8nMYEtw4_hMv92GE>nv6M9HAU376qqWBug z4Mfl6jz!Z&DX08pybP|7;NY5%e*cVJ_Wc383k<6*qiw`#n2)=EeTpC<(ZCD=bJ@+x zuyfBO%1mo(DwV6AOPipUNHf4ZG|dF5VZ!WzchG`0tn)G+BXTW zPS^6xI#sw~b+@_Rym`ZHY5}L*1bO10ym5wd@Vx+xI)9KOI`hf^zBkK%qD2Et4*87@ zjEUM%=<(K6-LH#b)W*N9mIG*L z=<0_}IZRD7x3+Q$933l1F{TnVBQ|c?=}jGKfMa=j*ruhml|Uf;@jd<%hlVFk1xSH$ zh3b7CWJp(W<)bVXdJ9lU*1v}x`WSRFdFrD;W~g(~;s5|2lZ!Jen@9ZI5Q95W6nS*x z_a^qO2L9Vha&&TvJL-6ev|oc&c=6L|Ug=9))s6Gqux>A)DfhaX)F-DE?NH}G>R=o+ zD@DrPjeoF`t%4v{AXxvOj2Ttkp}klCGY2M-Wj!LP*qfom38FS&zH7deN0;f&e3EWy zZcZ_N+Y19m%jEz}L{XW7!!UzhY7u12@{bH3N06nBVR=8rDP^`{A>iyaV_Q4BvsT>K zw-Zx=t^2dOWMOg{k5{32#?DVy5t;qys6wefu`d z(-_x}+oAg50iMYjU&-I8-`9UMSkzfzwp4I{9hq3#&$b`rO+tc2^Xm(M(n4}}`iimL zInI<&*`g;@W=otg^&AYAhy&LJ>@Xi{!|AH3s?5+Ar^868soI{*8}*G%rHiR(SS^Md zU*=`3N1h2l)q##?DYO3_=jEKtJe|56EPy~O_@*`L$~JfVZOAa zqT~IiE1>BTZSYqJXJ0DH&SmnUhiEEu!_MEEvs0?vui=iVC~I+Yt_ukQ3@e=PW)~TQ z&ToHb3uSoTa|*CnzRRPDWL98EGW8iv&GE#s(Z`Io#6o9HIpW$MUsG*m zlO;-EUT+Ny9Acr#N`hx{6%6Ax&c`xlQRtMEl=tJ=9oBVm^hPb&*aI>z|GqOdZf|B2 z*}PLBy(D_d)U|9|Pui-T0+Q1MMvR2YTCkGATge~GsM^S}16*29;PXD(W?UrOXd^j^tJy@%HP*^?Lbx!+$J`?S~n z^DO7$@)y+6sjWpXYEjiHCW`{r%502;hMd(e@{_U_rggg%?%0u?^&=sPWBM4-TXW4I zN*7{QNpTPnO-O0?XOG0%jIMHSeB5BtdZ z0(Wi9M3AjYb-a^0_V%MH^PPvWm5=iC^Al~3nXS^wULP46o6V@d+MuOQ#Cq}(72q4$ zB^6<<5$wmbQLoL+9VpzRXvw(b=MoVfB*m*rv_ZBRCu?zz_Pih?m=4uXeYSMpDDGy~}ot2X#%M31D zR_OCVTr#;|Z&--~B{hVX0N{HVYZ9B zpTibGZXr7A`yv%@Swhk1jBx9Cix558Vr3J9N@B(c6TxwJTa`j=!ewS%!gRbzWV(`K zmS%|d%7V=GiD0dz@IUT~o`QJgEox~}K!PMDU&42seKtWe-(!=XM^w>^-Q?%KyI0Ud zp)>1LdVWr>u$qK2?H@@`81YMBXi~iU?r{~rzVHJ4KR2lMRrmcNcx%v1jy=V=d;LJ5M?XrcT7Riwf3WE4E)g5; zbr;n`M%ZJUMH9+PVv1=*+tw?NbX&LLDIE%@`_`^7uSzt|uADY*lb|aZ7hPVYlQhUf zP=ToOq0h_!s5JX)*RC;BQa^7}(UWlGw~CQz`M?TZV!3IYv0`i-gsz|sm<|{4X8B== zqCyA&8y<>g7z`PlU9f!gIF-MvHTJ>qk#lW}1xQ+2S_1a6SMQai7IK{jZY)H}Y5x6E zZ5jR$DbzublqkV;PUGtJ>Oq(1fbq{&-0pJmwc9 z{2cidUwKngZHLonI~$dLzW!s-mqFj>K!IS^LAlxi6^nm`**7 zT55P_+XNQQq=CM^s1oSEUzqyu-*`4k!wo;QWDc1=&Q(0!U&X8{Fkm3rR)sVS0)YuV zU6m~0zKKK_)1WAxL4fQBc_DyXR#sMC8A$yC5=jRCJrqORoyUB?N6_iBtr$)b$iov# zeCOCy+Vp@;NyxCb7kD|Zx~PIJL7c)u>R-S$UV9k6P!8u#RG{+k_K@b@ve0;+fu~9n zxt1*{CX1u+ItDmYmo8j*8?Zd*R2z5pB{R=74O5mxM2S@xPkgah{iM&{=Qr9rIy6{s zZsZu5ZU(oaSgZaaLiG!5Yxor|2OQ$fB9Jk98P}b%F==BXpgsroD60w6;b!3Xn5h#&b8TNoG`n){7s!9gweaN?ez zJAwAg;ufni!P#!NPt$fe`Uj=Yb?He1(;dH&}Jo^sF(_?iQK;XaK1{z z!*HzkTl18E1^EH?ieTP+U(%a5m*7_+6?`zJ4B^$BL4a81MZ&NOnDnD0gN5$$COiYc<`z4j zXW;3D9~pum@3_&8ZvUB@I{$&g!ybzGdN410^wAM_z&O~CDWW~Ki5pJuwzxT_Bdg^7 z{VQ1EI|Kw~_*gi0cmToBjZ;2`YiNm4h5Z+Epg15r+>D$D1xP7E6Y3~RO5X|Cok@dD zhA_}LLWNfwoekUVi=(WZ(`C4zP7HB)qavzC2No22VmSdR>Kxn>$4r_c>(3o1(Az~FOB z%K$Ia3k1%~Rm_BnZ>OZBK{oS4UK3QtJS%Z@7vZUuuCMW*4;d^2N**wZcGz?6N;COcatKG|!Ar^oTU$mqOD-5lkbG2hG>V$Q zc~3}15f3p+M|-=XFdPI0gm6`5B~vg5Tz9L5J6VEBTfA%^qVdP4y@e%$2dy&4V1Iy9 z#GxZw`q!rm$q=3sn}*@mbgp|jZgepY1hjVaQEBt{xh3%yZVuYJGmMs>9JCCaiKh53 zHN^`Zwyy3cU{pQFzBmVrqJy>wj<`JO8rJ@|%S>?xEl`?a=5AZ zq6n4AAA&>>1$G|Tcg!dOOhAcv|3k~dhYKR^0Ih&c2s(_zxFfcWP-9_2Dln@L!ukdL zs8cX2`xQUch3~9IW+`?jum%zQ@tYg3`Pj{=n)p)w5{gx)cBGy7Q`<}o@I$AM#g{VI ztzh#hNXS>RzoVx@v zua(T0rA3SxO`?BSM!Yhn3ZRUfwq(i$GmX5tn=l;)c%`JIoMA1Fs~A4#k=a|N!ZcXl zV8<*JztWC=EQ?{puPnwV8>ae>BoQ-|+^VE=pnGV#e{-YgJ${lKne%|PhuNSlnPJuA zGzM>s)3Ar{L}y;Kyfff&GPtANTZrvx-Cppozm3zy{Iqtcuj(+;n>Up$qPv%Ou*34& zm`nFaX203o1OXEX@Dgo={%te8?zaljLcD`JL3g8&x`QUHk&G z2ZwrO9u->$S1G7MX>#%(xZL;g9^iW|j@$}Gb&Ct4 z#V4It#fXK4g+)b0;Fdx3Z1xzNj?rAG^(u;3*25b5`7J*`8LG}YPr>09MsKz`YVVeT zX$D1AxWZV5eL-3QdAXo-322eJc^k}EFK}4#T#DpF%~0^MN^)PKdh1KfByZKgQk}v+ zDJi($?XV?9{~m;@mY!(K9E5FzeiNJ6YvWn1;tFU@NPaPkl|~uZ#jiIxAZsvC>;gH932?3?1%>tm`<|5?{M2!(WiSyb~NA}{= zVb`kDPt8hY?u%uf-p$m#TUJj!7ck+DgHgcf5oTEY$p&b!kTVQ)y0Y7@ zi9HT-m@#)R=6U%URK@&Y=WSu*M!j%HV4f6XC^tpRTSR-oaa&mkTge6dPA28Q0gt<| zkUj={$@c*O@F>9EgUz*aNJPZrFYT%!1*=tXsfS)WQc&5+uKV!uIKM z#5PzB%$U5gO&y##4OWr)O`^~umGr!~K?U`b@-TMa0b>RJwr75N2}mM4pUjvrN;04f zM=QrMd;6A-8FMd#ox3f~YFkLvWqa<%_V%S3=RkMZHOh;G%d{&C*(TV1@$&?gnGFLL zPJ%P40LunWZ(qH#h93g>SECvM*Z;a+IG{QXI5b(qO_+jB*-7Rds)Jnuh)=fgfBluE ztTu3)Gz=A3`*MZ|vnP$SbiW5oSS+|HP_K0I$})M)x{aogY1+gGcqZ&|TrFE_E4(2r v6F1=wZAY$`2LHD#4ga&XkAJ!Wy@;!;+1N| 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 diff --git a/tests/expected/matlab/sanity_checks.m b/tests/expected/matlab/sanity_checks.m index 7a04f00..f336865 100644 --- a/tests/expected/matlab/sanity_checks.m +++ b/tests/expected/matlab/sanity_checks.m @@ -12,7 +12,7 @@ figure('name', 'histogram R2') hist(R2(:), 100); -print('histogram_R2.tif', '-depsc','-tiff'); +print('histogram_R2.png', '-dpng'); figure('name', 'R2') imagesc(R2, [0 100]) From ca4048875f29258e9debb74d50dd5d4cb650ab7c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:52:03 +0200 Subject: [PATCH 27/29] try testing different os and matlab version --- .github/workflows/run_tests_matlab.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_tests_matlab.yaml b/.github/workflows/run_tests_matlab.yaml index f62fdc0..88ea085 100644 --- a/.github/workflows/run_tests_matlab.yaml +++ b/.github/workflows/run_tests_matlab.yaml @@ -18,13 +18,20 @@ on: jobs: tests: - runs-on: ubuntu-latest + + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + matlab-version: ["R2020a", "R2021a"] + fail-fast: false # Don't cancel all jobs if one fails + + runs-on: ${{ matrix.os }} steps: - - name: Install MATLAB + - name: Install MATLAB ${{ matrix.matlab-version }} uses: matlab-actions/setup-matlab@v1.0.1 with: - release: R2020a + release: ${{ matrix.matlab-version }} - name: Shallow clone GLMsingle uses: actions/checkout@v3 From 882cf8e0a4d7d7929751a9634737a5303ffcecf6 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Fri, 8 Apr 2022 21:59:31 +0200 Subject: [PATCH 28/29] only run tests on ubuntu latest with matlab 2020a --- .github/workflows/run_tests_matlab.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run_tests_matlab.yaml b/.github/workflows/run_tests_matlab.yaml index 88ea085..561f208 100644 --- a/.github/workflows/run_tests_matlab.yaml +++ b/.github/workflows/run_tests_matlab.yaml @@ -21,8 +21,8 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - matlab-version: ["R2020a", "R2021a"] + os: [ubuntu-latest] # "macos-latest" or "windows-latest" don't work (yet?) + matlab-version: ["R2020a"] # add more versions if needed: "R2021a" fail-fast: false # Don't cancel all jobs if one fails runs-on: ${{ matrix.os }} From 4ae81fdc625ce5b2d39c659a7575e86d6f4a293b Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Tue, 12 Apr 2022 17:38:14 +0200 Subject: [PATCH 29/29] Update .github/workflows/run_tests_matlab.yaml --- .github/workflows/run_tests_matlab.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests_matlab.yaml b/.github/workflows/run_tests_matlab.yaml index 561f208..544ad9f 100644 --- a/.github/workflows/run_tests_matlab.yaml +++ b/.github/workflows/run_tests_matlab.yaml @@ -12,7 +12,7 @@ name: MATLAB tests on: push: # TODO only run on master branch on push - branches: ["*"] + branches: ["main"] pull_request: branches: ["*"]